在Chrome中推送和弹出冻结的数组,而不会引发异常

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

本文关键字:数组 异常 冻结 Chrome      更新时间:2023-09-26

以下代码在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之间的区别,然后我意识到这可能是因为严格的pop模式和push方法。总而言之,在Firefox(SpiderMonkey(中,poppush方法是在严格模式下定义的,但在Chrome(V8(中,这些方法不是在严格模式下定义的。

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

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

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

....

  • O是调用ToObject传递 this 值作为参数的结果。
  • 让我们lenVal调用[[Get]]内部方法的结果,O参数"length"。
  • n ToUint32(lenVal).
  • 让我们items是一个内部列表,其元素按从左到右的顺序是传递给此函数调用的参数。
  • 重复,当项目不为空时
    • 从项目中删除第一个元素,E元素的值。
    • 调用[[Put]]内部方法O参数 ToString(n)E true
    • n增加 1。
  • 调用 O 的[[Put]]内部方法,参数为"length"、n 和 true。
  • 返回 n。

请注意参数 3 到 [[Put]] 是如何true的。现在,[[Put]]定义为

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

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

  • 如果调用[[CanPut]] O P 参数的内部方法的结果是 false ,则
    • 如果Throw true,则引发TypeError异常。
    • 否则返回。

然后,[[CanPut]] 返回 false 等,如果是数组,则O [[Extensible]] false

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

更新:

Chrome开发人员正在谈论使pushpop严格模式下运行;然而,区别不仅仅是"严格"与"非严格",因为push的行为和pop在ECMA 262 5.1规范中非常具体地指定。