14

What is the rationale behind this behaviour?

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

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

Perhaps this was a genuine mistake. Which section of the ECMAScript specification defines this behaviour?

4

2 回答 2

14

实际上,在严格模式下,这不会发生,如您在此处看到的那样。

如果您阅读ECMA 标准的第 10.6 节,特别是注 1,您会看到:

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

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

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

于 2013-05-06T00:39:12.557 回答
8

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

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

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

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

  4. 调用 map 的 [[DefineOwnProperty]] 内部方法传递ToString (indx),属性描述符{[[Set]]: p , [[Get]]: g , [[Configurable]]: true } 和false作为参数.

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

f()  // undefined, undefined (no argument, no getter/setter)
f(1) // 1, 42
于 2013-05-06T00:47:59.113 回答