是否无法使用arguments属性设置尚未提供的参数

时间:2013-07-04 21:14:03

标签: javascript

我在测试东西。并发现如果我没有提供它,我无法设置参数。 使用arguments[1]

示例:

function abc (a,b) {
arguments[1] = 'new value';
console.log(b);
}
abc('a');

它无效。

我知道我可以像if (b=='undefined') b='default';那样设定值,但为什么我不喜欢这样。换句话说,这种行为是出乎意料的,不是吗?

另一方面,如果你提供参数,它会被改变!

这样调用函数会输出新值

abc('a','b');

是否有解决方案,如果您想使用arguments[2]设置值并在调用函数时传递参数。

经过更多测试后,似乎b如果没有被调用,则无法与arguments[1]建立关联。

4 个答案:

答案 0 :(得分:1)

我的理解是参数是动态的,其长度由提供给函数的参数/参数的数量来设定。

在第一种情况下,您只提供了一个参数,因此参数的大小为1,因此参数[1]应该超出范围,而在第二种情况下,您有长度为2的参数,因此您可以更改任一参数值使用它的索引。

答案 1 :(得分:1)

在发布了一个非常错误的答案后,我看了ECMA Spec,这里是代码,当arguments对象被创建时,JavaScript会做什么:

function abc () {
    var names = ["a", "b"];  //as normally provided in the function declaration: function (a, b)
    var a, b;
    var args = {};
    var mappedNames = [];
    args.length = arguments.length;
    var index = args.length - 1;

    //this is the crucial part. This loop adds properties to the arguments object
    //and creates getter and setter functions to bind the arguments properties to the local variables
    //BUT: the loop only runs for the arguments that are actually passed.
    while (index >= 0) {
        var val = arguments[index];
        if (index < names.length) {
            var name = names[index];
            if (mappedNames.indexOf(name) === -1) {
                mappedNames.push(name);
                var g = MakeArgGetter(name);
                var p = MakeArgSetter(name);
                Object.defineProperty(args, index.toString(), {get : g, set : p, configurable : true});
            }
        } 
        args[index.toString()] = val;
        index--;
    }

    function MakeArgGetter(name) {
        return function zz(){
            return eval(name);
        };
    }

    function MakeArgSetter(name) {
        return function tt(value) {
            eval(name + " = value;");
        };
    }

    console.log(args[0]);   //ab
    args[0] = "hello";  
    args[1] = "hello";
    console.log(a);         //hello      
    console.log(b);         //undefined

}
abc('ab');

请注意,Spec中还有更多内容,我在这里和那里简单地说它,但这基本上就是发生了什么。

答案 2 :(得分:0)

你想通过这个来实现什么目标?

如果你想让abc('a)abc('a', 'b')这样的“动态参数”都有效,但是第一个将缺少的参数设置为默认值,你要么必须检查参数长度和/或所有参数值。

假设有以下内容:abc('a', null),那么呢? - 取决于逻辑,可以是好的但也可能是坏的。

鉴于此,检查参数向量并不聪明,但更加神秘,并且if (b=='undefined') b='default'更加直观,更易于理解。

答案 3 :(得分:0)

TL; DR:每个ECMA规范都不可能,因为arguments只绑定到与提供的参数匹配的形式参数。建议仅引用arguments而不是改变它。

示例:http://jsfiddle.net/MattLo/73WfA/2/


关于参数

非严格arguments对象是 FormalParameterList 的双向映射对象,它是根据提供的参数数量生成的列表,这些参数映射到目标函数中定义的参数确定指标/表达。

  

当控制进入功能代码的执行上下文时,除非(如10.5中所指定)标识符参数作为函数的FormalParameterList中的标识符出现或作为函数中包含的VariableDeclaration或FunctionDeclaration的标识符出现,否则创建自变量对象。码。 ECMA 5.1规范(截至2014年3月26日)

arguments变量/变量到arguments

当调用方法时,仅在内部存在参数到变量的映射。映射是不可变的,并且在每个实例调用目标函数时创建。当use strict标志在函数范围内可用时,也会禁用两者之间的更新绑定。 arguments严格地成为参考,不再是更新参数的方法。

  

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

length怎么样?

arguments.length最初可以作为一个指标,用于确定满足多少正式参数,但由于arguments可以在length没有自动更新的情况下进行更改,因此不安全。 length无法更新,因为它不是真正的数组,因此不会遵守Array规范。