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.
thismeaningwindowin the global context is a bug that has been fixed, at least in Firefox)