Understanding JavaScript’s this keyword

(In Portugese)

The JavaScript this keyword is ubiquitous yet misconceptions abound.

What you need to know
Every execution context has an associated ThisBinding whose lifespan is equal to that of the execution context and whose value is constant. There are three types of execution context: global, function and evaluation. Here’s a tabular summary followed by a little more detail, and some examples:

Execution Context Syntax of function call Value of this
Global n/a global object (e.g. window)
Function Method call:
myObject.foo();
myObject
Function Baseless function call:
foo();
global object (e.g. window)
(undefined in strict mode)
Function Using call:
foo.call(context, myArg);
context
Function Using apply:
foo.apply(context, [myArgs]);
context
Function Constructor with new:
var newFoo = new Foo();
the new instance
(e.g. newFoo)
Evaluation n/a value of this in parent context

1. Global context
this is bound to the global object (window in a browser)

alert(this); //window


2. Function context
There are at least 5 ways to invoke a function. The value of this depends on the method of invocation

a) Invoke as a method
this is the baseValue of the property reference

var a = {
    b: function() {
        return this;
    }
};

a.b(); //a;

a['b'](); //a;

var c= {};
c.d = a.b;
c.d(); //c

b) Invoke as baseless function call
this is the global object (or undefined in strict mode)

var a = {
    b: function() {
        return this;
    }
};

var foo = a.b;
foo(); //window

var a = {
    b: function() {
        var c = function() {
            return this;
        };
        return c();
    }
};

a.b(); //window

The same applies to self invoking functions:

var a = {
    b: function() {
        return (function() {return this;})();
    }
};

a.b(); //window

c) Invoke using Function.prototype.call
thisis passed by argument

d) Invoke using Function.prototype.apply
this is passed by argument

var a = {
    b: function() {
        return this;
    }
};

var d = {};

a.b.apply(d); //d

e) Invoke a constructor using new
this is the newly created object

var A = function() {
    this.toString = function(){return "I'm an A"};
};

new A(); //"I'm an A"

 
3. Evaluation context
this value is taken from the this value of the calling execution context

alert(eval('this==window')); //true - (except firebug, see above)

var a = {
    b: function() {
        eval('alert(this==a)');
    }
};

a.b(); //true;

What you might want to know
This section explores the process by which this gets its value in the functional context – using ECMA-262 version 5.1 as a reference.

Lets start with the ECMAScript definition of this:

The this keyword evaluates to the value of the ThisBinding of the current execution context.

from ECMA 5.1, 11.1.1

How is ThisBinding set?

Each function defines a [[Call]] internal method (ECMA 5.1, 13.2.1 [[Call]]) which passes invocation values to the function’s execution context:

The following steps are performed when control enters the execution context for function code contained in function object F, a caller provided thisValue, and a caller provided argumentsList:
1. If the function code is strict code, set the ThisBinding to thisValue.
2. Else if thisValue is null or undefined, set the ThisBinding to the global object.
3. Else if Type(thisValue) is not Object, set the ThisBinding to ToObject(thisValue).
4. Else set the ThisBinding to thisValue

from ECMA 5.1, 10.4.3 Entering Function Code (slightly edited)

In other words ThisBinding is set to the object coercion of the abstract argument thisValue, or if thisValue is undefined, the global object (unless running in strict mode in which case thisValue is assigned to ThisBinding as-is)

So where does thisValue come from?

Here we need to go back to our 5 types of function invocation:

1. Invoke as a method
2. Invoke as baseless function call

in ECMAScript parlance these are Function Calls and have two components: a MemberExpression and an Arguments list.

1. Let ref be the result of evaluating MemberExpression.
2. Let func be GetValue(ref).
6. If Type(ref) is Reference, then
  a. If IsPropertyReference(ref) is true
    i. Let thisValue be GetBase(ref).
  b. Else, the base of ref is an Environment Record
    i. Let thisValue be the result of calling the ImplicitThisValue concrete method of GetBase(ref).
8. Return the result of calling the [[Call]] internal method on func, providing thisValue as the this value and
providing the list argList as the argument values

from ECMA 5.1, 11.2.3 Function Calls

So, in essence, thisValue becomes the baseValue of the function expression (see step 6, above).

In a method call the function is expressed as a property, so the baseValue is the identifier preceding the dot (or square bracket).

foo.bar(); //foo assigned to thisValue
foo[‘bar’](); //foo assigned to thisValue

var foo = {
    bar:function() {
        //(Comments apply to example invocation only)
        //MemberExpression = foo.bar
        //thisValue = foo
        //ThisBinding = foo
        return this;
    }
};
foo.bar(); //foo 

A baseless function is either a function declaration or a variable – in either case the baseValue is the Environment Record (specifically a Declarative Environment Record). ES 5.1, 10.2.1.1.6 tells us that the ImplcitThisValue of a Declarative Environment Record is undefined.

Revisiting 10.4.3 Entering Function Code (see above) we see that unless in strict mode, an undefined thisValue results in a ThisBinding value of global object. So this in a baseless function invocation will be the global object. In strict mode the ThisBinding remains undefined.

In full…

var bar = function() {
    //(Comments apply to example invocation only)
    //MemberExpression = bar
    //thisValue = undefined
    //ThisBinding = global object (e.g. window)
    return this
};
bar(); //window

3. Invoke using Function.prototype.apply
4. Invoke using Function.prototype.call

(specifications at 15.3.4.3 Function.prototype.apply and 15.3.4.4 Function.prototype.call)

These sections describe how, in call and apply invocations, the actual value of the function’s this argument (i.e. its first argument) is passed as the thisValue to 10.4.3 Entering Function Code. (Note this differs from ECMA 3 where primitive thisArg values undergo a toObject transformation, and null or undefined values are converted to the global object – but the difference will normally be negligible since the value will undergo identical transformations in the target function invocation (as we’ve already seen in 10.4.3 Entering Function Code))

5. Invoke a constructor using new

When the [[Construct]] internal method for a Function object F is called with a possibly empty list of arguments, the following steps are taken:
1. Let obj be a newly created native ECMAScript object.
8. Let result be the result of calling the [[Call]] internal property of F, providing obj as the thisValue and providing the argument list passed into [[Construct]] as args.
10. Return obj.

from ECMA 5.1, 13.2.2 [[Construct]]

This is pretty clear. Invoking the constructor with new creates an object that gets assigned as the thisValue. It’s also a radical departure from any other usage of this.

House Cleaning

Strict mode
In ECMAScript’s strict mode, the thisValue is not coerced to an object. A
this value of null or undefined is not converted to the global object and primitive values are not converted to wrapper objects

The bind function
Function.prototype.bind is new in ECMAScript 5 but will already be familiar to users of major frameworks. Based on call/apply it allows you to prebake the thisValue of an execution context using simple syntax. This is especially useful for event handling code, for example a function to be invoked by a button click, where the ThisBinding of the handler will default to the baseValue of the property being invoked – i.e. the button element:

//Bad Example: fails because ThisBinding of handler will be button
var sorter = {
    sort: function() {
        alert('sorting');
    },
    requestSorting: function() {
        this.sort();
    }
}
$('sortButton').onclick = sorter.requestSorting;
//Good Example: sorter baked into ThisBinding of handler
var sorter = {
    sort: function() {
        alert('sorting');
    },
    requestSorting: function() {
        this.sort();
    }
}
$('sortButton').onclick = sorter.requestSorting.bind(sorter);

Further Reading
ECMA 262, Edition 5.1
11.1.1 Definition of this
10.4.3 Entering Function Code
11.2.3 Function Calls
13.2.1 [[Call]]
10.2.1.1 Declarative Environment Record (ImplicitThisValue)
11.1.1 [[Construct]]
15.3.4.3 Function.prototype.apply
15.3.4.4 Function.prototype.call
15.3.4.5 Function.prototype.bind
Annex C The Strict Mode of ECMAScript

34 thoughts on “Understanding JavaScript’s this keyword

  1. Good overview, congrats.

    In addition, don’t forget some subtle cases such when seems that we have your case (a) Invoke a property, but thisValue isn’t set to base of reference, because there is no reference:

    [js]
    foo.bar(); // foo
    (foo.bar)(); // foo
    (foo.bar = foo.bar)(); // global
    (foo.bar || foo.baz)(); // global
    (function () {})(); // global
    [/js]

    Dmitry.

    1. Hi Dmitry – thanks for your feedback.
      These are good examples – I covered self-invoking functions already – I will try to incorporate the others

  2. One of the common stumbles for new JavaScripters 🙂

    … and also why I prefer closures to objects. It’s just generally more concise and robust (don’t need to worry about what context the function might be called in eventually) if you use closures instead of properties of `this`.

    Personally, I prefer this version of your example:

    var sorter = (function () {
        var sort = function() {
            alert('sorting');
        };
        return function(ev) {
            sort(ev.target);
        };
    }());
    $('sortButton').onclick = sorter;
    

    Keep these articles coming Angus 🙂

    1. Yep totally agree. Closures ftw! Sometimes the value of this seems to verge on arbitrary. Google “javascript this keyword”: nobody can really encapsulate the meaning without meandering off into edge cases.

      Peter Michaux includes ‘this’ as a JavaScript warning word
      http://peter.michaux.ca/articles/javascript-warning-words
      and wrote a nice piece about this free widget definition
      http://peter.michaux.ca/articles/javascript-widgets-without-this

  3. Thanks for helping de-voodoofying this 🙂

    I think I’ll be making references to functions instead of blindly doing .bind(this) – it’s measureably faster even in Chrome (with the new native bind)

  4. I would also add that `with` statement — quite expectedly — makes for confusing behavior when it comes to `this` value:

    For example, normally you would think that `foo()` invokes `foo` with `this` value referencing Global object; however, when executed as part of a `with` statement, `this` might well reference an object inserted into the scope chain.

    var obj = { foo: function(){ return this }};
    with(obj) {
      foo(); // `this` now references `foo` object, not Global one
    }
    
  5. Is this complexity intentional?
    If yes, what are the use cases they wanted to address?

    I really can’t understand why someone wanted such a mess to be in a programming language!

  6. Hi, syntax error in line 1 in the third type of execution context(Evaluation context): missing right parenthesis.

    correct
    alert(eval('this==window'));

  7. In example 2 E, is the last line supposed to have a comment?

    Perhaps

    new A(); "I'm an A"

    should be

    new A(); //"I'm an A"

    Also, do you have an example for 2 C?

    Thanks for the article!

    1. Hi Bob

      Yeah thanks for pointing that out – fixed now!

      2c is almost identical to 2d

      var a = {
          b: function() {
              return this;
          }
      };
      
      var d = {};
      
      a.b.call(d); //d
      
  8. Howdy! I know this is somewhat off topic but I was wondering if you knew where I could locate a captcha plugin for my comment form?
    I’m using the same blog platform as yours and I’m having problems finding one?
    Thanks a lot!

Leave a comment