在Chrome中对冻结数组进行push和pop操作不会抛出异常

4

以下代码在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个回答

6

ECMA 262 5.1指出了Array.prototype.push的以下内容:

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

....

  • 将调用该函数的对象转换为对象类型,赋值给变量O
  • 调用O的内部方法[[Get]],参数为字符串"length",将返回值赋值给变量lenVal
  • lenVal转换为32位无符号整数类型,赋值给变量n
  • 创建一个内部列表items,将该函数调用时传入的所有参数按从左到右的顺序依次添加到列表中。
  • 重复以下步骤,直到items为空:
    • items中移除第一个元素,并将其赋值给变量E
    • 调用O的内部方法[[Put]],参数分别为ToString(n)Etrue
    • n的值加1。
  • 调用O的内部方法[[Put]],参数为字符串"length"、ntrue
  • 返回n
请注意,[[Put]]的第三个参数为true。现在,[[Put]]的定义如下:

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

当调用对象O[[Put]]内部方法时,传入属性P、值V和布尔标志Throw。执行以下步骤:

  • 如果使用参数P调用O[[CanPut]]内部方法的结果为false,那么
    • 如果Throwtrue,则抛出一个TypeError异常。
    • 否则返回。

...

在数组的情况下,如果O上的[[Extensible]]false,则[[CanPut]]将返回false等其他值。

因此,您的Chrome 违反了 ECMA 262 5.1规范。 更新: Chrome开发人员正在讨论使pushpop在严格模式下运行。然而,差异不仅仅在于“严格”与“非严格”,因为pushpop的行为在ECMA 262 5.1规范中被具体指定了。

抱歉,我的英语不太好,您的纠正对我很有帮助。 - Hoshinoma Araki

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接