Cases where 'this' is the global Object in Javascript

I'm playing around with different ways to call a function that is an attribute of an Object in Javascript and looking at which type of calls set 'this' to be the Object and which set 'this' to be the Global Object.

This is my test code:

var foo = {
  bar: function(){ 
    console.log('this:' + this);
  }
}

console.log('calling foo.bar()');
foo.bar();

console.log('\ncalling (foo.bar)()');
(foo.bar)();

console.log('\ncalling f=foo; f.bar()');
f = foo; f.bar();

console.log('\ncalling f=foo.bar; f()');
f = foo.bar; f();

console.log('\ncalling (f=foo.bar)()');
(f = foo.bar)();

And this is the result:

calling foo.bar()
this:[object Object]

calling (foo.bar)()
this:[object Object]

calling f=foo; f.bar()
this:[object Object]

calling f=foo.bar; f()
this:[object global]

calling (f=foo.bar)()
this:[object global]

My question is, why does f=foo.bar; f(); and (f=foo.bar)(); assign 'this' to be the Global Object


The key of knowing the implicit behavior of this on function calls, relies on knowing how the Reference Type woks.

The Reference Type consists of two components (in ECMAScript 3), the base object and the property name (in ECMAScript 5, it has a third component the strict flag -I will talk about strict mode later- (1)).

When a function is invoked, the this value is determined implicitly by getting the base object of the reference (by the internal GetBase operation).

For example, in the foo.bar reference, the base object is foo and the property name is "bar":

foo.bar(); // `this` will point to `foo`

When you do an assignment, the reference is lost, we don't have anymore a base object and a property name, we just have a value:

(f=foo.bar)(); // `this` will point to the global object

It doesn't happen only with assignments, it happens with other operations that use the internal GetValue operation:

// `this` will point to the global object    
(0, foo.bar)();   // The Comma Operator
(0 || foo.bar)(); // Binary Logical Operators
(1 && foo.bar)();
// etc..

It doesn't happens for example if you surround a reference with parentheses (formally called The Grouping Operator):

(foo.bar)(); // `this` will point to `foo`

The Grouping Operator (again, the parentheses ;) doesn't use GetValue internally, this was designed in that way because the typeof and delete operators are allowed to work with parenthesised expressions:

delete (foo.bar);

If the grouping operator used GetValue, the delete operator would be unable to get a base object where to remove the property bar.

Returning to the implicit this value, there are some tricky cases, for example, using the with statement:

with (foo) {
  bar(); // `this` will refer to `foo` !
}

As you can see, invoking bar(); inside the with block, will still bind the this value to the foo object.

The this value isn't set from the reference, it comes from the current Environment Record (I'll maybe write something about it later) introduced by the with statement.

Also, as you may note, for non-references, the this value will point to the global object, for example:

(function () {})(); // this will point to the global object

We just have a value, not a reference (Remember, a reference is a resolved name binding).


(1)NOTE: On ECMAScript 5 Strict Mode, the this value will be undefined for all the cases described where the this value is set implicitly to the Global object.

This was made as a security measure mostly due the fact that people often forgot to use the new operator when invoking constructor functions, causing a bad behavior and pollution on the global scope.

For example:

function Foo () {
  this.prop = 'foo';
}
Foo(); // no `new` operator, boom!

As you known now, the Foo reference doesn't have a direct base object, this will point to the global object and it will unintentionally create a property on it.

On Strict Mode, the code would simply give you a TypeError, because the this value would be undefined.

Also as you may remember in the beginning I mentioned that the Reference Type has a third component, the strict flag.

Your original example:

(f=foo.bar)();

Would probably not even work on Strict Mode, because assignments to undeclared identifiers (such as f seems) are disallowed, (another security measure to avoid global object pollution).

More info:

  • Strict Mode

In the first 3 examples you use the foo object and run its function, thus you get the context from which the function is run, an Object, the foo object.

In the last 2 examples you copy the foo.bar function to the variable f and execute it. In this case the function is executed from the global context, not from the foo Object context. It would be the same as declaring and running

  function f() { 
    console.log('this:' + this);
  }

Referencing ECMA-262 (edition five) which is probably difficult to follow (emphasis added):

10.2.1.2 Object Environment Records

Object environment records can be configured to provide their binding object as an implicit this value for use in function calls. This capability is used to specify the behaviour of With Statement (12.10) induced bindings. The capability is controlled by a provideThis Boolean value that is associated with each object environment record. By default, the value of provideThis is false for any object environment record.

10.2.1.2.6 ImplicitThisValue()

Object Environment Records return undefined as their ImplicitThisValue unless their provideThis flag is true.

  1. Let envRec be the object environment record for which the method was invoked.
  2. If the provideThis flag of envRec is true, return the binding object for envRec.
  3. Otherwise, return undefined.

10.4.3 Entering Function Code

  1. If the function code is strict code, set the ThisBinding to thisArg.
  2. Else if thisArg is null or undefined, set the ThisBinding to the global object.

10.4.1.1 Initial Global Execution Context

The following steps are performed to initialize a global execution context for ECMAScript code C:

  1. Set the VariableEnvironment to the Global Environment.
  2. Set the LexicalEnvironment to the Global Environment.
  3. Set the ThisBinding to the global object.

10.4.2 Entering Eval Code

The following steps are performed when control enters the execution context for eval code:

  1. If there is no calling context or if the eval code is not being evaluated by a direct call (15.1.2.1.1) to the eval function then,
    1. Initialize the execution context as if it was a global execution context using the eval code as C as described in 10.4.1.1.
  2. Else,
    1. Set the ThisBinding to the same value as the ThisBinding of the calling execution context.

11.1.1 The this Keyword

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

11.2.3 Function Calls

The production CallExpression : MemberExpression Arguments is evaluated as follows:

  1. Let ref be the result of evaluating MemberExpression.
  2. Let func be GetValue(ref).
  3. Let argList be the result of evaluating Arguments, producing an internal list of argument values (see 11.2.4).
  4. If Type(func) is not Object, throw a TypeError exception.
  5. If IsCallable(func) is false, throw a TypeError exception.
  6. If Type(ref) is Reference, then
    1. If IsPropertyReference(ref) is true, then
      1. Let thisValue be GetBase(ref).
    2. Else, the base of ref is an Environment Record
      1. Let thisValue be the result of calling the ImplicitThisValue concrete method of GetBase(ref).
  7. Else, Type(ref) is not Reference.
    1. Let thisValue be undefined.
  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.

12.10 The with Statement

  1. Let oldEnv be the running execution context’s LexicalEnvironment.
  2. Let newEnv be the result of calling NewObjectEnvironment passing obj and oldEnv as the arguments
  3. Set the provideThis flag of newEnv to true.

this is assigned to the global object if:

  1. thisArg is null or undefined when calling a function. thisArg is set:
    1. By the first argument of Function.prototype.apply (15.3.4.3).
    2. By the first argument of Function.prototype.call (15.3.4.4).
    3. By the first argument of Function.prototype.bind (15.3.4.5) (not in ECMA252-3).
    4. By calling using the MemberExpression Arguments syntax, meaning:
      1. foo(arguments) is equivalent to foo.call((function() { }()), arguments); iff foo is callable and if you're not in a with statement.
      2. foo.bar(arguments) is equivalent to foo.bar.call(foo, arguments), evaluating foo only once, iff foo.bar is callable.
  2. The context is the global context, which occurs:
    1. In the default scope.
    2. In the scope of eval if it is being called directly.

My question is, why does f=foo.bar; f(); and (f=foo.bar)(); assign 'this' to be the Global Object

This is detailed under section 11.2.3, step 6.a.i (6.1.1 above); ref is the f expression in your case (not its value), and GetBase(ref).ImplicitThisValue() is undefined (as a variable has an object environmental record as its base with provideThis set to false if that variable does not come from with).