js-arguments 函数参数对象详解

前言

  JavaScript 函数参数不同于其他编程语言,既不需要规定参数的类型,也不需要关心参数的个数,因此 JavaScript 因函数参数而变得十分灵活,本文总结一下 arguments 参数对象的相关知识点。

正文

  1、arguments参数对象是什么

  JavaScript 中函数既不需要关心传入的参数个数,也不需要关心这些参数的数据类型。正因为这一特性,JS函数没有重载。因此定义函数的时要接收两个参数,并不意味着就要传入两个参数,你可以传入一个、三个,甚至一个也不传,编译器都不会报错。arguments对象是一个类数组对象(但是不是Array 的实例),因此可以使用括号语法来访问其中的元素,要确定元素的个数,可以访问 arguments.length 属性。

    function foo() {
      console.log(arguments);
      for (let i = 0; i < arguments.length; i++) {
        console.log(arguments[i]);
      }
    }
    foo(1, 2, 3, "a") 
    //  0: 1
    //  1: 2
    //  2: 3
    //  3: "a"
    //  callee: ƒ foo()
    //  length: 4
    //  Symbol(Symbol.iterator): ƒ values()
    //  [[Prototype]]: Object
    // 1 2 3 "a"    

  ECMAScript 函数的参数只是为了方便才写出来的,并不是必须写出来的,可用通过arguments[0]...访问, arguments 对象可以跟命名参数一起使用。

    foo(1, 2, 3, "a")
    function foo(name, age) { 
      console.log(name, arguments[1]) 
    }
    foo(1,2) // 1 2

 

  2、参数默认值

  JS 中函数可以接收任意数量的参数,而无视函数声明处的参数数量,但是有时候需要为传递参数设置默认值。在ES6 之前,我们的代码如下设置默认值:
       function getValue(value){
          value = value || 100
          return value
      }
      console.log(getValue())//100这里使用了默认值100
      console.log(getValue(0))//100 这里入参为0的时候

  在ES6之后提供了非常方便的设置默认值方法:

        function getValue(value = 100) {
          return value;
        }
        console.log(getValue()); //100
        console.log(getValue(0)); //0
        console.log(getValue(null)); //null null默认值是有效的

 

  3、参数传递和接收

  这里主要写一下ES6 之后常用的参数传递的快捷方法,先来看下面代码:

        function getSum() {
            var sum = 0
            for (let i = 0; i < arguments.length; ++i) {
                sum += arguments[i];
            }
            return sum;

        }
        console.log(getSum(...[1, 2, 3])); // 6

  上面的代码中,getSum方法入参为一个数组,通过扩展运算符分别传入,这种写法比较常见。前面我们提到arguments对象为一个类数组对象,下面的代码中通过扩展运算符将类数组对象转为数组,如下:

       function getSum(...values) {
            console.log(arguments);
            console.log(values);
            // 顺序累加 values 中的所有值
            // 初始值的总和为 0
            return values.reduce((x, y) => x + y, 0);
        }
        console.log(getSum(1, 2, 3)); // 6

  运行结果如下:

 

  4、函数作为参数和返回值

  因为函数名在 JS 中就是变量,所以函数可以用在任何可以使用变量的地方。这意味着不仅可以把函数作为参数传给另一个函数,而且还可以在一个函数中返回另一个函数。

        function creatSum(addSum, num) {
            return addSum(num)
        }
        function addSum(num) {
            return num + 10
        }
        var sum = creatSum(addSum, 1)
        console.log(sum);//11 

 

  5、箭头函数中参数问题

  箭头函数中没有 arguments 对象,但可以在包装函数中把它提供给箭头函数。

  箭头函数虽然不支持 arguments 对象,但支持收集参数的定义方式,因此也可以实现与使用 arguments 一样的逻辑。

    function foo() {
      let bar = () => {
        console.log(arguments[0]); // 5
      };
      bar();
    }
    foo(5);

 

  6、arguments.callee 使得函数逻辑和函数名解耦

  解决上面的问题可以首先来看一道题:通过一个函数求传入参数的阶乘值。一般的解决思路如下:

       function foo(num) {
            if (num <= 1) {
                return 1;
            } else {
                return num * foo(num - 1);
            }
        }
        console.log(foo(5));//120

  但是别的地方引用该函数的时候,不免会发生错误:

        function foo(num) {
            if (num <= 1) {
                return 1;
            } else {
                return num * foo(num - 1);
            }
        }
        console.log(foo(5));//120
        let anotherFoo = foo
        foo = null
        console.log(anotherFoo(5)); // 报错 foo is not a function

  在写递归函数时使用 arguments.callee 可以避免这个问题。

        function foo(num) {
            if (num <= 1) {
                return 1;
            } else {
                return num * arguments.callee(num - 1);
            }
        }
        console.log(foo(5)); //120
        let anotherFoo = foo
        foo = null
        console.log(anotherFoo(5)); //120

  不过,在严格模式下运行的代码是不能访问 arguments.callee 的,因为访问会出错。此时,可以使用命名函数表达式达到目的。

        let foo = (function f(num) {
            if (num <= 1) {
                return 1;
            } else {
                return num * f(num - 1);
            }
        });
        console.log(foo(5));//120
        let anotherFoo = foo
        foo = null
        console.log(anotherFoo(5));//120

  上面的代码创建一个函数表达式发 f()赋值给变量 foo ,即使函数赋值给了另一个变量,函数表达式f不变,因此递归就不会有调用的问题了。

写在最后

  以上就是本文的全部内容,希望给读者带来些许的帮助和进步,方便的话点个关注,小白的成长踩坑之路会持续更新一些工作中常见的问题和技术点。

 

 

posted @ 2021-11-07 15:57  zaisy'Blog  阅读(966)  评论(0编辑  收藏  举报