Javascript:函数参数和参数[]

时间:2013-05-22 20:50:08

标签: javascript function arguments

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

我正在通过'专业Javascript for Web Developers'和第3章“理解参数”部分,讨论使用参数[]关键字访问函数参数。

其中一个示例显示您可以修改参数[]:

中的值
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中发生了哪些变化?

谢谢,

尼尔

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

3 个答案:

答案 0 :(得分: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 is there to help的更多详情。我没有查看那里的所有代码示例,但是AFAIKT没有有效更改 arguments对象的代码。
前段时间我想我读了一篇关于这个问题的道格拉斯·克罗克福德的文章,他举了一个例子,说明如何更改arguments对象实际上会导致意外行为(参数交换位置等等)。

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

答案 1 :(得分: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规范解决了section 10.6上的问题:

  

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

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

有趣的事实:函数中存在eval调用会影响参数对象在某些浏览器中的行为,这非常奇怪。使用非标准functionName.arguments参考也会产生影响。请参阅Why does an unexecuted eval have an effect on behavior in some browsers?,以及我对它的回答。

答案 2 :(得分:1)

只有在严格的模式下它才能正常工作..

 "use strict" 
  

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

     

function f(x){       的console.log(X); //显示参数的初始值       arguments [0] = null; //更改数组元素也会改变x!       的console.log(X); //现在显示“null”}这显然不是您在Arguments对象中看到的行为   是一个普通的阵列。在这种情况下,参数[0]和x可以参考   最初是相同的值,但改变为1将没有任何效果   另一方面。

     

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

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

我建议你使用它:)