3

我是 Javascript 新手,所以请原谅基本问题。

我正在研究“面向 Web 开发人员的专业 Javascript”,在第 3 章“理解参数”部分,它讨论了使用 arguments[] 关键字访问函数参数。

其中一个示例表明您可以修改 arguments[] 中的值:

function twoNums(num1, num2) {
    arguments[1] = 10;
    console.log(arguments[0] + num2);
}

twoNums(4,8);  output = 14

但它继续说“这种效果只有一种方式:更改命名参数不会导致参数中相应值的更改。”

但是,将代码更改为:

function twoNums(num1, num2) {
    num2 = 10;
    console.log(arguments[0] + arguments[1]);
}

twoNums(4,8);  output = 14

产生相同的输出,因此“arguments[1]”中的值肯定会发生变化。

这是:

  • 书中有错误?
  • 我的理解有误?
  • 自本书写作以来,Javascript 发生了哪些变化?

谢谢,

尼尔

回答:答案的组合解决了我的问题。感谢大家。

4

3 回答 3

2

从表面上看,书中有一个错误:如果您重新分配传递的任何参数,则arguments对象将更改(两者都引用相同的值)。
不过,也许书中的意思是这样的:

function f(n1, n2)
{
    arguments[0] = 2;
    console.log(arguments[0] + arguments[1]);
}
f(1, 2);//logs 4
f(1234,2);//logs 4

但是,老实说,这应该不重要。该arguments对象应被视为只读对象。在 JS 中坚持“不要更改你不拥有的对象”的口头禅是个好主意。尝试更改 是一个坏主意,因为通过随机删除和添加方法来更改任何对象 ( , ...)Object.prototype的行为并不是最好的主意。consolewindow

如果您想获得更多详细信息arguments,或者MDN 可以提供任何其他帮助。我还没有查看那里的所有代码示例,但是 AFAIKT 没有有效地更改arguments对象的代码。
前段时间我想我读了一篇关于这个问题的 Douglas Crockford 的文章,他在其中举了一个例子,说明改变arguments对象实际上会导致意外行为(参数交换位置等等)。

编辑:
我以为我不会进入严格模式,但正如 bfavaretto 的回答所指出的那样:严格模式实际上确实使arguments对象成为只读对象。这是一个了不起的消息,现在我更有理由喜欢 JS 的发展方式。ES6 将引入块作用域,并可能使arguments对象一直只读(至少,我希望如此)。

于 2013-05-22T20:58:32.507 回答
2

它应该以这种方式工作,除非在严格模式下:

function foo(a) {
    "use strict";
    console.log(a, arguments[0]);
    a = 10;
    console.log(a, arguments[0]);
    arguments[0] = 20;
    console.log(a, arguments[0]);
}
foo(1);

// output:
// 1 1
// 10 1
// 10 20

ES5 规范在第 10.6 节解决了这个问题:

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

也许它在 ES3(以前的版本)上的工作方式不同,但我对此表示怀疑(因为他们必须为严格模式添加一个特殊情况)。

有趣的事实:eval函数中调用的存在会影响参数对象在某些浏览器中的行为,这非常奇怪。使用非标准functionName.arguments参考也会产生影响。请参阅为什么未执行的 eval 会对某些浏览器中的行为产生影响?,以及我对此的回答。

于 2013-05-22T20:59:11.700 回答
1

它只会在严格模式下以这种方式工作..

 "use strict" 

Arguments 对象有一个非常不寻常的特性。在非严格模式下,当函数具有命名参数时,Arguments 对象的数组元素是保存函数参数的参数的别名。Arguments 对象的编号元素和参数名称就像同一个变量的两个不同名称。使用参数名称更改参数的值会更改通过 arguments[] 数组检索到的值。相反,通过 arguments[] 数组更改参数的值会更改由参数名称检索的值。这是一个澄清这一点的例子:

函数 f(x) { console.log(x); // 显示参数的初始值 arguments[0] = null; // 改变数组元素也会改变 x! 控制台.log(x); // 现在显示“null” } 如果 Arguments 对象是一个普通数组,这显然不是您会看到的行为。在这种情况下,arguments[0] 和 x 最初可以引用相同的值,但对其中一个的更改不会对另一个产生影响。

在 ECMAScript 5 的严格模式中,Arguments 对象的这种特殊行为已被删除。还有其他严格模式的差异。在非严格函数中,参数只是一个标识符。在严格模式下,它实际上是一个保留字。严格模式函数不能使用参数作为参数名或局部变量名,也不能为参数赋值。

这是关于这个主题的一篇很棒的(最近的)文章: https ://www.inkling.com/read/javascript-definitive-guide-david-flanagan-6th/chapter-8/function-arguments-and

我建议你使用它:)

于 2013-05-22T21:04:25.163 回答