为什么的JavaScript对象的参数通过转让突变为参数?(Why are JavaScript A

2019-09-02 01:13发布

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

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

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

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

Answer 1:

事实上,在严格模式下,这不会发生,因为你可以在这里看到 。

如果你读了第10.6 ECMA标准 ,特别注意1,你会看到:

对于非严格模式的功能的自变量指定的数组索引(在15.4定义的)数据的属性的对象,其数字名称值小于相应的功能对象的形式参数的数目最初与在该函数的相应参数绑定共享它们的值执行上下文。 这意味着,改变属性改变参数结合和反之亦然的相应值。 如果这样的属性被删除该对应被破坏,然后重新定义或如果该属性改变为存取器属性。 对于严格模式的功能,参数对象的属性的值进行简单的传递给函数的参数副本,并有属性值和形式参数值之间没有动态链接。

总之,这是什么想说的是,在非严格模式,命名函数参数在项目别名操作arguments对象。 因此,改变一个命名参数的值将改变等效值arguments项,反之亦然。 这是不是一个错误。 这是预期行为。

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



Answer 2:

改变x反映在arguments[0]因为索引arguments可以是用于匹配命名参数吸气/ setter方法 。 这是在确定的10.6步骤11.c.ii :

  1. 添加名称列表mappedNames的元素。

  2. g是调用的结果MakeArgGetter带参数的名称env抽象操作。

  3. p为调用的结果MakeArgSetter带参数的名称env抽象操作。

  4. 调用图的[[DefineOwnProperty]]内部方法传递的ToString (INDX),所述属性描述符 {[[设置]为:p,[[获取]]: ,[[配置]]: }, 作为参数。

正如在上面的步骤指出的,这要求严格的假的 ,并且在这种情况下, f调用与一个值x

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


文章来源: Why are JavaScript Arguments objects mutated by assignment to parameter?