在Chrome中的冻结阵列上推送并弹出不会引发异常

Hos*_*aki 4 javascript ecma262 ecmascript-5

以下代码似乎在Chrome下未按预期运行,并且在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);
})();
Run Code Online (Sandbox Code Playgroud)

我预计输出将是:

Error : (for `arr.push(4)`)
Error : (for `arr.pop()`)
[1, 2, 3]
Run Code Online (Sandbox Code Playgroud)

但是当在Chrome 29.0.1547.49(官方版本216092)beta-m上运行此代码时,我收到以下输出:

3
[1, 2, 3]
Run Code Online (Sandbox Code Playgroud)

为什么没有例外?我在Firefox Nightly 26.0a1(2013-08-12)上运行了这段代码,结果是

TypeError: arr.push(...) is not extensible
TypeError: property arr.pop(...) is non-configurable and can't be deleted
[1, 2, 3]
Run Code Online (Sandbox Code Playgroud)

正如我所料.

我想到了为什么Chrome和Firefox之间存在差异,然后我意识到这可能是因为严格的模式poppush方法.综上所述,在Firefox(SpiderMonkey)poppush方法中都是以严格模式定义的,但在Chrome(V8)中这些方法并没有在严格模式下定义.

我不知道实际的规格是什么.(我读了一些ECMA-262第5.1版,但我找不到这样的部分.)

Ant*_*ala 6

ECMA 262 5.1说明如下Array.prototype.push:

15.4.4.7 Array.prototype.push ( [ item1 [ , item2 [ , … ] ] ] )

....

  • 让我们O调用ToObject传递this值作为参数的结果.
  • 让我们lenVal调用带有参数" " 的[[Get]]内部方法的结果.Olength
  • 我们nToUint32(lenVal).
  • items是一个内部列表,其内容是,在从左到右的顺序,分别传递给这个函数调用的参数.
  • 重复,而项目不为空
    • 从items中删除第一个元素,并将E其作为元素的值.
    • 调用[[Put]]的内部方法O与参数ToString(n),Etrue.
    • 增加n1.
  • [[Put]]使用参数"length",n和true 调用O 的内部方法.
  • 返回

注意参数3 [[Put]]是如何的true.现在,[[Put]]被定义为

8.12.5 [[Put]] ( P, V, Throw )

当使用property ,value 和Boolean标志调用[[Put]]内部方法时,将执行以下步骤:OPVThrow

  • 如果调用 with参数的[[CanPut]]内部方法的结果是,那么 OPfalse
    • 如果Throwtrue,则抛出TypeError异常.
    • 别的回归.

...

[[CanPut]]然后返回false其他,如果[[Extensible]]在数组的情况下Ofalse.

因此,您的Chrome 违反了ECMA 262 5.1规范.

更新:

Chrome开发人员正在谈论制作push,pop在严格模式下运行; 然而所不同的是不只是"严格的"与"非严格"为行为pushpop在ECMA 262 5.1规范非常具体地指定.