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

Is it not possible to set arguments that have not been provided, using arguments property

本文关键字:参数 设置 属性 arguments 是否      更新时间:2023-09-26

我在测试一些东西。我发现,如果我没有提供论据,我就无法设置论据。使用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]设置值并传递参数,是否有解决方案。

经过更多的测试,似乎:如果不调用barguments[1]就无法连接。

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

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

在发布了一个非常错误的答案后,我查看了ECMA规范,代码中显示了当创建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');

请注意,规范中还有一些内容,我只是在这里和那里简单地介绍了一下,但这基本上就是正在发生的事情。

您试图通过此实现什么?

如果您希望像abc('a)abc('a', 'b')这样的"动态参数"都有效,但第一个参数会将缺少的参数设置为默认值,则必须检查参数长度和/或所有参数值。

假设给出以下内容:abc('a', null),然后是什么?-取决于逻辑,可以是好的,也可以是坏的。

考虑到这一点,检查自变量向量并不是更聪明,而是更神秘,而且像if (b=='undefined') b='default'这样的东西更直接、更容易理解。

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标志在函数范围内可用时,也会禁用两者之间的更新绑定。CCD_ 17成为严格的参考,而不再是更新参数的方式。

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

length

arguments.length最初可以是确定满足多少形式参数的指标,但这是不安全的,因为arguments可以在length不自动更新的情况下更改。length不更新,因为它不是真正的阵列,因此不符合Array规范。