Function.prototype.apply() & Function.prototype.call() with `undefined` or `null` as `thisArg`
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 thethis
value. This is a change from Edition 3, where aundefined
ornull
thisArg
is replaced with the global object andToObject
is applied to all other values and that result is passed as thethis
value.It seems like modern engines still have the ES3 behavior:
function foo() { console.log(this); return this; }; foo.call(undefined) === undefined; //
false
, expectedtrue
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…
- a wilful violation of the ES5 spec for back-compat reasons, or…
- is it just an oversight that this never got implemented, or…
- 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
Turns out this is a bug in the spec: ecmascript#2370
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.
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
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
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
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:
It seems like modern engines still have the ES3 behavior:
I’ve tested this in Spidermonkey/Firefox, Carakan/PrestOpera, JSC/Safari, and v8/Chrome. They all show FAIL in this test case:
Is this…
If 1 is the case, the ES6 spec should match reality by reverting the change introduced in ES5.