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

时间:2013-08-13 04:40:51

标签: javascript ecmascript-5 ecma262

以下代码似乎未在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);
})();

我预计输出会是:

Error : (for `arr.push(4)`)
Error : (for `arr.pop()`)
[1, 2, 3]

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

3
[1, 2, 3]

为什么没有例外?我在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]

正如我所料。

我想到了为什么Chrome和Firefox之间的区别,然后我意识到这可能是因为poppush方法的严格模式。总而言之,在Firefox(SpiderMonkey)中poppush方法是在严格模式下定义的,但在Chrome(V8)中,这些方法没有在严格模式下定义。

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

1 个答案:

答案 0 :(得分:6)

ECMA 262 5.1说明了以下Array.prototype.push

  

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

     

...

     
      
  • O成为调用ToObject传递此值作为参数的结果。
  •   
  • lenVal成为使用参数“[[Get]]”调用O length内部方法的结果。
  •   
  • n成为ToUint32(lenVal)
  •   
  • items成为一个内部List,其元素按从左到右的顺序排列为传递给此函数调用的参数。
  •   
  • 重复,而项目不为空   
        
    • 从项中删除第一个元素,并让E为元素的值。
    •   
    • 使用参数[[Put]]O ToString(n) 调用E true内部方法。
    •   
    • n增加1。
    •   
  •   
  • 使用参数“length”,n和true调用O的[[Put]]内部方法。
  •   
  • 返回n。
  •   

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

  

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

     

使用属性[[Put]]调用O P的内部方法时,   值V和布尔标志Throw,执行以下步骤:

     
      
  • 如果调用带有参数[[CanPut]]的{​​{1}}的{​​{1}}内部方法的结果是 O ,那么   
        
    • 如果Pfalse,则抛出Throw例外。
    •   
    • 别的回归。
    •   
  •   
     

...

true然后返回TypeError等数据,如果[[CanPut]]上的false[[Extensible]],则返回数组。

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

<强>更新

Chrome开发人员正在讨论如何在严格模式下运行Ofalse;然而,差异不仅仅是“严格”与“非严格”,因为pushpop的行为在ECMA 262 5.1规范中具体指定。