美文网首页
JavaScript中那些容易忽视的Arguments细节

JavaScript中那些容易忽视的Arguments细节

作者: 晴天小雨不感冒 | 来源:发表于2020-03-18 17:30 被阅读0次

    arguments实参列表

    和目前业界流行的各种编程相比(如C,C++,Java,C#),Javascript函数的arguments属性别具一格。它使JavaScript在进行函数调用时更具灵活性。在其他语言中,如果函数形参列表和调用时的实参列表不匹配(参数类型或者参数个数不一致),那么程序就无法编译通过。以C语言代码为例:

    void add()
    {}
    add(1, 2);
    

    以上代码会在代码编译时报错,C++,Java,C#也同样会报错。因为add函数在声明时是无参的,而在实际调用时却向函数传递了两个数值参数。这是很典型的形参列表和实参列表不一致,大多数编程语言都将其视为语法错误。但是在JavaScript中,情况却不是这样,JavaScript解释器不但不将其视为语言错误,而且还能正常地向无参函数传递参数。这一切都是因为有arguments属性的存在。如下面的JavaScript代码:

    void add()
    {
        console.log(arguments[0] + arguments[1]);
    }
    add(1, 2);
    

    结果为3。因为有arguments,形参列表就显得不重要了,反正最后的计算以实参列表为准。我们在调用时甚至以add(1),add(1,2,3)调用也不会报错,总之,想怎么传就怎么传,只要函数中的计算没有逻辑错误就可以。例如add(1),虽然解释器在语法分析时不会报错,但却会在运行时报错,因为实际计算用到的参数和传递的参数不一样,这是很典型的逻辑错误。我们可以对上述函数进行一些改造,以达到传递任何数量的参数都可以计算总值的目的。代码如下:

    void add()
    {
        let sum = 0;
        for(let i = 0; i < arguments.length; i++)
        {
            sum += arguments[i];
        }
        console.log(sum);
        
    }
    add();//结果:0
    add(1);//结果:1
    add(1, 2);//结果:3
    add(1, 2, 3);//结果:6
    

    arguments的引用特性

    arguments是一个类似数组的对象,和数组不一样的是,arguments的length不具有数组的length的特殊行为,数组可以通过设置length改变数组大小,而arguments不能改变自身大小。更为特殊的是arguments的引用特性。何为arguments的引用特性《JavaScript权威指南》上这样解释:Arguments对象和参数名为引用同一个值提供了两种途径。用参数名改变参数的值,会同时改变Arguments对象获取的值,反之,用Arguments改变参数的值也会改变参数名的值。不妨以代码为例:

    function Fun(x, y)
    {
        var arr = new Array();
        arr[0] = y;
    
        arr[0] = 4;
        arguments[0] = 4;
        console.log(x, y);//打印 4,2
    }
    Fun(1,2);
    

    在上述代码中,arr是一个数组,arguments是类数组对象。arr[0]引用了y,arguments[0]引用了x,我们对引用的值进行修改,结果是x的值被修改了,而y的值没有修改。实际上, arr[0] = y并没有传递y值本身,而是传递了y的一个副本,因此在运行时, arr[0] 和y实际上是两个数值,因此改变 arr[0] 不会影响y。而arguments[0]和x却是指向同一个值,两个中任何一个改变另外一个也会跟着改变。这就是arguments的引用特性。它使得值类型的参数具有引用类型的特征。这一点很重要,却容易被人忽略。

    形参和实参的严格匹配

    尽管在JavaScript中参数传递更加随意灵活,但有时候我们也需要添加一定的限制,比如我们效仿其他语言的做法,让形参列表和实参列表必须完全匹配,否则返回错误。在这里我们需要用到callee对象,它表示函数自身,callee对象的length属性表示函数形参列表的个数。因此我们可以用它和arguments.length比较。如果一样,则表示形参列表和实参列表一致,允许调用,如果不一样,则表示形参列表和实参列表不一致,抛出错误。因为JavaScript是弱类型语言,形参并不规定类型,因此这里的严格匹配只是做参数个数匹配,不匹配类型。代码如下:

    function check(args)
    {
        var actual = args.length;//实参个数
        var exped = args.callee.length;//形参个数
        if(actual != expected)
        {
            throw new Error("参数列表不匹配,期望值:" + exped + " 实际值:" + actual);
        }
    }
    function fun(x, y, z)
    {
        check(arguments);//实际计算前先检查形参和实参是否匹配
        return x + y + z;
    }
    fun(1);//报错
    fun(1, 2);//报错
    fun(1, 2, 3);//打印 6
    fun(1, 2, 3, 4);//报错
    

    好了,关于arguments的内容就是这些,你是否都掌握了呢?

    相关文章

      网友评论

          本文标题:JavaScript中那些容易忽视的Arguments细节

          本文链接:https://www.haomeiwen.com/subject/glecyhtx.html