Let's look at the ECMAScript 5 specification for Array.prototype.sort
:
Let obj be the result of calling ToObject passing the this
value as the argument.
And when we examine ToObject, we see a familiar entry in the table:
Argument Type Result
============= ======
Undefined Throw a TypeError exception.
...
Object The result is the input argument (no conversion).
This suggests that Chrome's invocation of b()
has a this
value that is not undefined
, but other browsers do pass a this
of undefined
, resulting in a TypeError
.
First we must examine how this
is set when we perform a function call (which EMCAScript refers to as a CallExpression):
- If Type(ref) is Reference, then
- If IsPropertyReference(ref) is
true
, then
- Let thisValue be GetBase(ref).
- Else, the base of ref is an Environment Record
- Let thisValue be the result of calling the ImplicitThisValue concrete method of GetBase(ref).
- Else, Type(ref) is not Reference.
- Let thisValue be
undefined
.
Because ImplicitThisValue of a function's Environment Record always returns undefined
, the only case in which this
is not undefined
is during property access, e.g., foo.bar()
. Therefore, we can conclude that the execution of a "bare" function invocation like b()
will always use a thisValue of undefined
.
But in the Chrome console, this
isn't undefined
for b()
. To understand how this could happen (and how it could differ between browsers), we need to examine strict mode behavior in Section 10.4.3, Entering Function Code:
The following steps are performed when control enters the execution context for function code contained in function object F, a caller provided thisArg, and a caller provided argumentsList:
If the function code is strict code, set the ThisBinding to thisArg.
Else if thisArg is null
or undefined
, set the ThisBinding to the global object.
where "ThisBinding" is "The value associated with the this
keyword within ECMAScript code associated with this execution context."
Thus, non-strict code replaces an null
or undefined
thisArg with the global object, window
. Strict mode, on the other hand, does not convert null
or undefined
to the global object when used for this
. (sort
returns the sorted this
object, so c = b()
simply stores the returned the global object into c
.)
Therefore, we can conclude that Firefox's implementation of the Array.prototype.sort
function runs in strict mode, while Chrome's implementation does not.
You can see further evidence of this by how sort
handles non-object this
values. If oyu run typeof []["sort"].apply(5)
in various browsers, Chrome will output "number"
, while Firefox outputs "object"
, demonstrating the object autoboxing that occurs only in non-strict mode. Firefox's strict sort
function does not box the 5
and returns the raw primitive.
this
meaningwindow
in the global context is a bug that has been fixed, at least in Firefox)