【发布时间】:2013-05-06 00:31:18
【问题描述】:
这种行为背后的原因是什么?
function f(x) {
console.log(arguments[0]);
x = 42;
console.log(arguments[0]);
}
f(1);
// => 1
// => 42
也许这是一个真正的错误。 ECMAScript 规范的哪一部分定义了这种行为?
【问题讨论】:
这种行为背后的原因是什么?
function f(x) {
console.log(arguments[0]);
x = 42;
console.log(arguments[0]);
}
f(1);
// => 1
// => 42
也许这是一个真正的错误。 ECMAScript 规范的哪一部分定义了这种行为?
【问题讨论】:
实际上,在严格模式下,这不会像you can see here那样发生。
如果您阅读ECMA Standard 的第 10.6 节,尤其是注 1,您会看到:
对于非严格模式函数,数组索引(在 15.4 中定义)命名参数对象的数据属性 其数值名称值最初小于相应函数对象的形参个数 与函数执行上下文中的相应参数绑定共享它们的值。这意味着改变 该属性更改参数绑定的相应值,反之亦然。如果该通信中断 这样的属性被删除然后重新定义,或者如果该属性更改为访问器属性。对于严格模式 函数,参数对象的属性值只是传递给函数的参数的副本,并且 属性值和形参值之间没有动态联系。
简而言之,这就是说,在非严格模式下,命名函数参数作为arguments 对象中项目的别名运行。因此,更改命名参数的值将更改等效arguments 项的值,反之亦然。这不是一个错误。这是预期的行为。
作为社论,依赖这种行为可能不是一个好主意,因为它会导致一些非常混乱的代码。另外,这样的代码,如果在严格模式下执行,将不再有效。
【讨论】:
更改x 反映在arguments[0] 中,因为arguments 的索引可能是匹配命名参数的getter/setters。这是在step 11.c.ii of 10.6 下定义的:
将 name 添加为列表 mappedNames 的元素。
让 g 成为使用参数 name 和 env 调用 MakeArgGetter 抽象操作的结果。
让 p 成为使用参数 name 和 env 调用 MakeArgSetter 抽象操作的结果。
调用map的[[DefineOwnProperty]]内部方法传递ToString(indx),Property Descriptor{[[Set]]:p,[[Get]]:g、[[Configurable]]:true} 和 false 作为参数。
如上述步骤所述,这要求 strict 为 false,在这种情况下,f 被调用值为x:
f() // undefined, undefined (no argument, no getter/setter)
f(1) // 1, 42
【讨论】: