这种行为背后的理由是什么?
function f(x) {
console.log(arguments[0]);
x = 42;
console.log(arguments[0]);
}
f(1);
// => 1
// => 42
也许这是一个真正的错误。 ECMAScript规范的哪个部分定义了这种行为?
答案 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:
将 name 添加为列表 mappedNames 的元素。
让 g 成为使用参数 name 和 env 调用MakeArgGetter抽象操作的结果。
让 p 成为使用参数 name 和 env 调用MakeArgSetter抽象操作的结果。
- 醇>
调用[[3}}(indx),[{3}} {[[Set]]: p ,[ [Get]]: g ,[[Configurable]]: true }, false 作为参数。
如上述步骤所述,这要求 严格 false ,在这种情况下,使用f
的值调用x
:
f() // undefined, undefined (no argument, no getter/setter)
f(1) // 1, 42