这种行为的基本原理是什么?为什么JavaScript Arguments对象通过赋值给参数而变异?
function f(x) {
console.log(arguments[0]);
x = 42;
console.log(arguments[0]);
}
f(1);
// => 1
// => 42
也许这是一个真正的错误。 ECMAScript规范的哪一部分定义了这种行为?
这种行为的基本原理是什么?为什么JavaScript Arguments对象通过赋值给参数而变异?
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
对象的项目进行操作。因此,改变一个命名参数的值将会改变等价物的值,反之亦然。这不是一个错误。这是预期的行为。
作为一篇社论,依靠这种行为可能不是一个好主意,因为它会导致一些非常混乱的代码。而且,这些代码如果在严格模式下执行,则不再有效。
改变x
反映在arguments[0]
由于arguments
索引可以是吸气/ setter方法用于匹配命名参数。这是step 11.c.ii of 10.6下定义:
添加名作为列表mappedNames的元素。
让克是调用带有参数名和ENV的MakeArgGetter抽象操作的结果。
让p是调用带有参数名和ENV的MakeArgSetter抽象操作的结果。
呼叫地图的[[DefineOwnProperty]]内部方法通过ToString(INDX),则Property Descriptor {[[设置]]:p,[[获取]]:克,[[配置]] :true}和false作为参数。
如在上面的步骤指出的,这要求严格是假和,在这种情况下,f
是带一个值x
:
f() // undefined, undefined (no argument, no getter/setter)
f(1) // 1, 42
对downvote的原因感到好奇 - 希望在可能的情况下改进答案。 – Dancrumb 2013-05-07 14:11:20