(draft) Understanding “this” keyword in ES6 from JavaScript spec

by ilyavf

ECMA-262 versions 5 and 6 are a bit different in defining “this” keyword. Lets see what will be changed with ES6 coming.

Quick dive into the 5th edition

 

For the 5th edition the best article I ever read was one by Angus Croll Understanding JavaScript’s this keyword. In the 2nd part of his article “What you might want to know” Angus explored the specification, and the resulting explanation is just brilliant. IMHO. Here is a brief and very simplified summary.

  1. 5th edition 11.1.1 The this Keyword: “The this keyword evaluates to the value of the ThisBinding of the current execution context“.
  2. ThisBinding is set to the object coercion of the abstract argument thisValue.
  3. thisValue comes from baseValue.
  4. And finally baseValue depends on the current execution context:
    1. baseValue is the identifier preceding the dot when function is expressed as a property.
    2. In a baseless function invocation thisValue results in a ThisBinding value of the global object (or undefined in strict mode).
    3. Invoking function as a constructor with new creates an object that gets assigned as the thisValue, so its the new instance.
    4. Invoking using Function.prototype.apply or .call will result in the 1st argument.

Some examples:

// as a method/property:
var foo = {
    bar: function() { return this ;}
}
foo.bar();         // -> foo

// baseless function:
var b = foo.bar;
b();               // -> window

// using constructor:
var user = new function () {
    this.getThis = function () { return this; }
}
user.getThis();    // -> user

For more examples you could look at Mozilla Developer Network resource: Web/JavaScript/Reference/Operators/this.

The easiest way to remember the most common cases is:

– If there is a “base” when you execute the function then “this” will result in the “base”.
– Without the “base” you will get the global object.

The most common use cases to get lost are:
– passing a function as an argument.
– using a function as an event handler.

The confusion comes when you do this and see the “base” before the method. But think this way – we are passing the reference, so when the function actually gets executed there will be no “base” any more. The words “execution context” should help to remember this.

var foo = {
    bar: function() { return this ;}
};
var z = function (f) {
    return f(); // here we don't have the "base"
};
z(foo.bar);     // -> window

Lets get our hands dirty in the 6th edition

 

6th edition 12.1.1 The this Keyword: “Return the result of calling the ResolveThisBinding abstract operation.”

Right away we can see they did something about it. Lets try to explore the full path.

12.1.1 The this Keyword
12.1.1.1 Runtime Semantics: Evaluation
PrimaryExpression : this
Return the result of calling the ResolveThisBinding abstract operation.

8.3.3 ResolveThisBinding
The abstract operation ResolveThisBinding determines the binding of the keyword this using the LexicalEnvironment of the running execution context. ResolveThisBinding performs the following steps:

Let env be the result of performing the GetThisEnvironment abstract operation.
Return the result of calling the GetThisBinding concrete method of env.

8.3.2 GetThisEnvironment
The abstract operation GetThisEnvironment finds the lexical environment that currently supplies the binding of the keyword this. GetThisEnvironment performs the following steps:

1. Let lex be the running execution context’s LexicalEnvironment.
2. Repeat
a. Let envRec be lex’s environment record.
b. Let exists be the result of calling the HasThisBinding concrete method of envRec.
c. If exists is true, then return envRec.
d. Let outer be the value of lex’s outer environment reference.
e. Let lex be outer.

NOTE The loop in step 2 will always terminate because the llst of environments always ends with the global environment which has a this binding.

Advertisements