为什么JavaScript Arguments对象通过赋值给参数而变异?

时间:2013-05-06 00:31:19

标签: javascript ecmascript-5

这种行为背后的理由是什么?

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

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

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

2 个答案:

答案 0 :(得分:14)

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

如果你阅读ECMA Standard的第10.6节,特别是注1,你会看到:

  

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

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

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

答案 1 :(得分:8)

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

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

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

  4.   
  5. p 成为使用参数 name env 调用MakeArgSetter抽象操作的结果。

  6.   
  7. 调用[[3}}(indx),[{3}} {[[Set]]: p ,[ [Get]]: g ,[[Configurable]]: true }, false 作为参数。

  8.   

如上述步骤所述,这要求 严格 false ,在这种情况下,使用f的值调用x

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