The following code does not seem to run as expected under Chrome, and runs differently in Firefox.
(function () {
'use strict';
var
arr = Object.freeze([1, 2, 3]);
try {
arr.push(4);
} catch (e) {
console.log(e);
}
try {
console.log(arr.pop());
}catch (e) {
console.log(e);
}
console.log(arr);
})();
I expected that the output would be:
Error : (for `arr.push(4)`)
Error : (for `arr.pop()`)
[1, 2, 3]
but when running this code on Chrome 29.0.1547.49 (Official Build 216092) beta-m, I receive the following output:
3
[1, 2, 3]
Why is there no exception? I ran this code on Firefox Nightly 26.0a1(2013-08-12), and the result is
TypeError: arr.push(...) is not extensible
TypeError: property arr.pop(...) is non-configurable and can't be deleted
[1, 2, 3]
as I had expected.
I thought about why the difference between Chrome and Firefox, then I realized that it could be because of strict mode of pop
and push
methods. To sum up, in Firefox (SpiderMonkey) pop
and push
methods are defined in strict mode, but in Chrome (V8) these methods isn't defined in strict mode.
I don't know what is the actual specification. (I read some ECMA-262 5.1th Edition, but I can't find such section.)
ECMA 262 5.1 says the following of Array.prototype.push
:
15.4.4.7
Array.prototype.push ( [ item1 [ , item2 [ , … ] ] ] )
....
- Let
O
be the result of callingToObject
passing the this value as the argument.- Let
lenVal
be the result of calling the[[Get]]
internal method ofO
with argument "length
".- Let
n
beToUint32(lenVal)
.- Let
items
be an internal List whose elements are, in left to right order, the arguments that were passed to this function invocation.- Repeat, while items is not empty
- Remove the first element from items and let
E
be the value of the element.- Call the
[[Put]]
internal method ofO
with argumentsToString(n)
,E
, andtrue
.- Increase
n
by 1.- Call the
[[Put]]
internal method of O with arguments "length", n, and true.- Return n.
Notice how the argument 3 to [[Put]]
is true
. Now, [[Put]]
is defined as
8.12.5
[[Put]] ( P, V, Throw )
When the
[[Put]]
internal method ofO
is called with propertyP
, valueV
, and Boolean flagThrow
, the following steps are taken:
- If the result of calling the
[[CanPut]]
internal method ofO
with argumentP
isfalse
, then
- If
Throw
istrue
, then throw aTypeError
exception.- Else return.
...
[[CanPut]]
then returns false
among others, in the case of array if [[Extensible]]
on O
is false
.
Thus, your Chrome is in violation of the ECMA 262 5.1 specification.
Update:
Chrome developers are talking about making the push
, pop
run under strict mode; however the difference is not just "strict" vs "non-strict" as the behaviour of push
and pop
is specified very specifically in the ECMA 262 5.1 specification.