July 9, 2011

The this keyword in JavaScript

What does this mean?
Short answer, it depends.

In general terms, you could say that the this keyword, in JavaScript, refers to the function's context, how it's invoked. There are four ways in which a function can be invoked: method form, function form, constructor form and apply form.

Method form
If a function is invoked in the method form, this will be bound to the object that owns the function:
var myObj = {
    name: 'Chuck',
    sayName: function () {
        return 'Hello ' + this.name;
    }
};

myObj.sayName(); // this refers to myObj, returns 'Hello Chuck'

Function form
This means taking a function value and calling it. In ECMAScript 3, this would be bound to the global object:
var myFunc = function () {
    return this.location.href;
};

myFunc(); // this refers to window (in browsers), returns the current URL
In ECMAScript 5 Strict Mode (almost fully supported), this was changed so that it would refer to undefined instead:
var myFunc = function () {
    'use strict';
    return this.location.href;
};

myFunc(); // error, this is undefined

Constructor form
A constructor is meant to be called using the new keyword, in this form, this will refer to the object being produced:
var MyConstructor = function (name) {
    this.name = name;
    this.sayName = function () {
        return 'Hello ' + this.name;
    };
};

var myObj = new MyConstructor('Chuck');
myObj.name; // 'Chuck'
myObj.sayName(); // 'Hello Chuck'

Apply form
Functions are objects and, as most objects, they have methods. This form refers to using the function's methods apply() or call() to call a function. Both methods take whatever first argument you pass and bound this to it. They differ in the way they provide the arguments to the function being invoked.
The apply() method takes an array of arguments:
var myObj1 = {
    name: 'Chuck'
};
var myObj2 = {
    name: 'Charles'
};
var sayWelcome = function (location) {
    return 'Hello ' + this.name + '. Welcome to ' + location;
};

sayWelcome.apply(myObj1, ['New York']); // 'Hello Chuck. Welcome to New York'
sayWelcome.apply(myObj2, ['Toronto']); // 'Hello Charles. Welcome to Toronto'
The call() method takes a list of arguments separated by commas:
sayWelcome.call(myObj1, 'New York'); // 'Hello Chuck. Welcome to New York'
sayWelcome.call(myObj2, 'Toronto'); // 'Hello Charles. Welcome to Toronto'

Summary
The value of this depends on the calling form:
  • Method form: it's bound to the object containing the method.
  • Function form: it's bound to either the global object (ECMAScript 3), or to undefined in (ECMAScript 5 Strict Mode).
  • Constructor form: it's bound to the new object being constructed.
  • Apply form: it's bound to the first argument passed to apply() or call().

Source:
Crockford on JavaScript - Act III: Function the Ultimate

4 comments:

  1. Don't forget subtle cases such as:


    var o = {m: function () { console.log(this); }}

    o.m(); // o
    (o.m)(); // o

    (o.m = o.m)(); // global
    (o.m || o.m)(); // global
    (o.m, o.m)(); // global

    You may find more info on this here: http://dmitrysoshnikov.com/ecmascript/chapter-3-this/

    ReplyDelete
  2. Easy way to remember the function/method breakdown? Functions always use "this" to refer to their parent scope. Since all "global" functions are members of the global object, "this" refers back to them:

    var window = { bob: function() { conosle.log(this) } }
    var some_obj = { bob: function() { conosle.log(this) } }

    Also of note? bind() is new in FF3.6+ Chrome 10+ and IE9+:
    https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind

    Brilliant stuff!

    ReplyDelete
  3. I always find the difficulty with the use of subtle cases with lot of complexity.Please share the best method of learning it simple and easier.
    Thank you !
    web design company

    ReplyDelete
  4. Thanks for the share. Keep posting such kind of information on your blog. I bookmarked it for continuous visit.
    html5 music player| html5 media player

    ReplyDelete