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 (Official Build 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.1th Edition,但我找不到这样的部分。)

4

1 回答 1

6

ECMA 262 5.1说明以下内容Array.prototype.push

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

……

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

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

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

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

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

...

[[CanPut]]然后返回false除其他外,在数组 if [[Extensible]]on Ois的情况下false

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

更新:

Chrome 开发者正在讨论让push,pop在严格模式下运行;然而,区别不仅仅是“严格”与“非严格”的行为,push并且pop在 ECMA 262 5.1 规范中非常具体地指定。

于 2013-08-13T06:11:59.340 回答