Push and pop on a frozen array in Chrome not throwing an exception

848 views Asked by At

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.)

1

There are 1 answers

1
Antti Haapala -- Слава Україні On BEST ANSWER

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 calling ToObject passing the this value as the argument.
  • Let lenVal be the result of calling the [[Get]] internal method of O with argument "length".
  • Let n be ToUint32(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 of O with arguments ToString(n), E, and true.
    • 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 of O is called with property P, value V, and Boolean flag Throw, the following steps are taken:

  • If the result of calling the [[CanPut]] internal method of O with argument P is false, then
    • If Throw is true, then throw a TypeError 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.