js-arguments 函式引數物件詳解

丶Serendipity丶發表於2021-11-07

前言

  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不變,因此遞迴就不會有呼叫的問題了。

寫在最後

  以上就是本文的全部內容,希望給讀者帶來些許的幫助和進步,方便的話點個關注,小白的成長踩坑之路會持續更新一些工作中常見的問題和技術點。

 

 

相關文章