【问题标题】:Why are JavaScript Arguments objects mutated by assignment to parameter?为什么 JavaScript Arguments 对象会因分配给参数而发生变异?
【发布时间】:2013-05-06 00:31:18
【问题描述】:

这种行为背后的原因是什么?

function f(x) {
  console.log(arguments[0]);
  x = 42;
  console.log(arguments[0]);
}

f(1);
// => 1
// => 42

也许这是一个真正的错误。 ECMAScript 规范的哪一部分定义了这种行为?

【问题讨论】:

    标签: javascript ecmascript-5


    【解决方案1】:

    实际上,在严格模式下,这不会you can see here那样发生。

    如果您阅读ECMA Standard 的第 10.6 节,尤其是注 1,您会看到:

    对于非严格模式函数,数组索引(在 15.4 中定义)命名参数对象的数据属性 其数值名称值最初小于相应函数对象的形参个数 与函数执行上下文中的相应参数绑定共享它们的值。这意味着改变 该属性更改参数绑定的相应值,反之亦然。如果该通信中断 这样的属性被删除然后重新定义,或者如果该属性更改为访问器属性。对于严格模式 函数,参数对象的属性值只是传递给函数的参数的副本,并且 属性值和形参值之间没有动态联系。

    简而言之,这就是说,在非严格模式下,命名函数参数作为arguments 对象中项目的别名运行。因此,更改命名参数的值将更改等效arguments 项的值,反之亦然。这不是一个错误。这是预期的行为。

    作为社论,依赖这种行为可能不是一个好主意,因为它会导致一些非常混乱的代码。另外,这样的代码,如果在严格模式下执行,将不再有效。

    【讨论】:

    • 对投反对票的原因感到好奇 - 希望在可能的情况下改进答案。
    【解决方案2】:

    更改x 反映在arguments[0] 中,因为arguments 的索引可能是匹配命名参数的getter/setters。这是在step 11.c.ii of 10.6 下定义的:

    1. name 添加为列表 mappedNames 的元素。

    2. g 成为使用参数 nameenv 调用 MakeArgGetter 抽象操作的结果。

    3. p 成为使用参数 nameenv 调用 MakeArgSetter 抽象操作的结果。

    4. 调用map的[[DefineOwnProperty]]内部方法传递ToString(indx),Property Descriptor{[[Set]]:p,[[Get]]:g、[[Configurable]]:true} 和 false 作为参数。

    如上述步骤所述,这要求 strictfalse,在这种情况下,f 被调用值为x

    f()  // undefined, undefined (no argument, no getter/setter)
    f(1) // 1, 42
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-08-26
      • 2012-09-08
      • 1970-01-01
      • 2016-08-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-02-24
      相关资源
      最近更新 更多