Function.prototype.apply() & Function.prototype.call() with `undefined` or `null` as `thisArg`

# Mathias Bynens (11 years ago)

From ecma-international.org/ecma-262/5.1/#sec-15.3.4.3 and ecma-international.org/ecma-262/5.1/#sec-15.3.4.4:

The thisArg value is passed without modification as the this value. This is a change from Edition 3, where a undefined or null thisArg is replaced with the global object and ToObject is applied to all other values and that result is passed as the this value.

It seems like modern engines still have the ES3 behavior:

function foo() {
  console.log(this);
  return this;
};
foo.call(undefined) === undefined; // `false`, expected `true`

I’ve tested this in Spidermonkey/Firefox, Carakan/PrestOpera, JSC/Safari, and v8/Chrome. They all show FAIL in this test case:

data:text/html,<script>function foo() { console.log(this); return this; }; document.write(foo.call(undefined) === undefined %3F 'PASS' %3A 'FAIL');</script>

Is this…

  1. a wilful violation of the ES5 spec for back-compat reasons, or…
  2. is it just an oversight that this never got implemented, or…
  3. am I misreading the spec?

If 1 is the case, the ES6 spec should match reality by reverting the change introduced in ES5.

# Claude Pache (11 years ago)

Le 10 déc. 2013 à 13:59, Mathias Bynens <mathias at qiwi.be> a écrit :

From ecma-international.org/ecma-262/5.1/#sec-15.3.4.3 and ecma-international.org/ecma-262/5.1/#sec-15.3.4.4:

The thisArg value is passed without modification as the this value. This is a change from Edition 3, where a undefined or null thisArg is replaced with the global object and ToObject is applied to all other values and that result is passed as the this value.

It seems like modern engines still have the ES3 behavior:

function foo() { console.log(this); return this; }; foo.call(undefined) === undefined; // false, expected true

I’ve tested this in Spidermonkey/Firefox, Carakan/PrestOpera, JSC/Safari, and v8/Chrome. They all show FAIL in this test case:

data:text/html,<script>function foo() { console.log(this); return this; }; document.write(foo.call(undefined) === undefined %3F 'PASS' %3A 'FAIL');</script>

Is this…

  1. a wilful violation of the ES5 spec for back-compat reasons, or…
  2. is it just an oversight that this never got implemented, or…
  3. am I misreading the spec?

If 1 is the case, the ES6 spec should match reality by reverting the change introduced in ES5.

The difference is perceptible only in strict mode code. In non-strict mode, undefined and null are still replaced by the global object, but at a later time relatively to what was specified in ES3; see: [10.4.3 Entering Function Code] (ecma-international.org/ecma-262/5.1/#sec-10.4.3)

―Claude

# Mathias Bynens (11 years ago)

Turns out this is a bug in the spec: ecmascript#2370

# Allen Wirfs-Brock (11 years ago)

On Dec 10, 2013, at 5:32 AM, Mathias Bynens wrote:

Turns out this is a bug in the spec: ecmascript#2370

I'll respond further when i deal with the actual bug report , but for now, I'm not sure I agree with your conclusion.

What you have been talking about (and what Annex C describes) is the end-to-end behavior of using call/apply to invoke a function. That includes the local semantics of call/apply, but also the semantics of various [[Call]] internal methods and the entry semantics of strict, non-strict, and built-in functions.

The Note attached to the spec. of the Call/Apply function is highlighting an essential change to their local semantics that was introduced in ES5. However, that local change has no effect on the observable end-to-end behavior of calling a non-strict function. It is observable for strict functions.

In general, you have to follow the spec. end-to-end to understand the end-to-end semantics.

Perhaps, it is reasonable to assume that implementation have already made the transition from ES3 to ES5 semantics and the local note is no longer need in the ES6 spec.

# Andrea Giammarchi (11 years ago)

and don't forget the lovely "de-stricter" ^_^

function wut() {
  'use strict';
  // oh wait, not anymore ...
  return Function('return this')();
}

wut() === window; // true

Anyway, trying to retrieve the native global a part, I don't think there's any other meaningful use case for having null or undefined "translated" into an object so "use strict" in this case (giving the possibility to retrieve the global via Function) is actually welcome: ES6 should follow, imo

# Oliver Hunt (11 years ago)

new Function is simply calling a constructor - the fact that it creates a callable object is irrelevant as there is nothing magical about the constructor itself.

The new function object itself is also scoped to the root lexical environment, not the strict mode function it is being called from, so it wouldn’t make sense for it to gain lexical state form the caller.

—Oliver

# Andrea Giammarchi (11 years ago)

I was NOT complaining about that and I know the behavior ... those double quotes were not there by accident.

"de-stricter" ^_^

was to point out that even inside a strict part of the code you can execute runtime out of strict code ... code so mine was a hint: if you don't use strict because you want the global object, use Function('return this')() instead and you are good to go