js之閉包(概念、優缺點、應用)

bailizx發表於2020-07-20

4.2 閉包

4.2.1 閉包的定義

閉包是指有權訪問另一個函式作用域中變數的函式。建立閉包的最常見的方式就是在一個函式A內建立另一個函式B,通過函式B訪問函式A區域性變數。(js高階教程)

4.2.2 閉包優缺點

1 閉包的作用(優點)

1)讀取另一個函式作用域中的變數;

2)讓這些變數始終保持在記憶體中,即閉包可以使得它誕生環境一直存在。

3封裝物件的私有屬性和私有方法。(然後在全域性作用域中通過呼叫閉包就能訪問函式中的變數)

2 閉包的缺點(壞處)

由於閉包會攜帶包含它的函式的作用域,因此會比其他函式佔用更多的記憶體,過度使用閉包可能會導致記憶體佔用過多的問題。

所以不能濫用閉包,否則會造成網頁的效能問題,在IE中可能導致記憶體洩露。解決方法是,在退出函式之前,將不使用的區域性變數全部刪除。

4.2.3 閉包的應用

閉包的應用—迴圈中使用閉包解決 var 定義函式的問題

/*變數i是var命令宣告的,在全域性範圍內都有效,所以全域性只有一個變數i。

  每一次迴圈,變數i的值都會發生改變,而迴圈內setTimeout的回撥函式中使用console.log(i),

  裡面的i指向的就是全域性的i。

*/

 

  for( var i=1; i<=5; i++) {

    setTimeout( function timer() {

        console.log( i );

    }, i*1000);

}  //輸出5個6

//因為 setTimeout 是個非同步函式,所有會先把迴圈全部執行完畢,這時候 i 就是 6 了,所以會輸出一堆 6。

解決方法

1)使用閉

for (var i = 1; i <= 5; i++) {
    (function(j) {
        setTimeout(function timer() {
            console.log(j);
        }, j * 1000);
    })(i);
} //1 2 3 4 5(每行一個數字)

2)使用 setTimeout 的第三個引數

for ( var i=1; i<=5; i++) {
    setTimeout( function timer(j) {
        console.log( j );
    }, i*1000, i);
}

3)使用let

for ( let i=1; i<=5; i++) {

    setTimeout( function timer() {

        console.log( i );

    }, i*1000 );

}

4.2.4 閉包的注意點:閉包中的this以及arguments物件(js高階程式設計)

this物件是在執行時基於函式的執行環境繫結的。

每一個函式在呼叫時都會自動取得兩個特殊的變數:this和arguments。內部函式在搜尋這兩個變數時,只會搜尋到其活動物件為止,因此永遠不可能直接訪問外部函式中的這兩個變數。不過,如果把外部作用域中的this和arguments物件儲存在一個閉包能夠訪問的變數裡面,就可以在閉包中訪問者兩個物件了。其應用可以看防抖節流、apply等手寫實現。

在下面的例子中物件obj中方法getName定義了一個閉包。使用obj.getName(18)呼叫閉包的外部函式,其getName中的thisarguments指向obj [Arguments] { '0': 18 }。在全域性中呼叫閉包,在非嚴格模式下的瀏覽器中,其this指向全域性物件window

var name = "outer";
var obj = {
    name: "inner",
    getName: function (age) {   //閉包
        console.log(this, arguments);  //  { name: 'inner', getName: [Function: getName] } [Arguments] { '0': 18 }
        return function () {
             return {
                 th: this,
                 age: age,
                 na: name,
                 arg: arguments
             }
        }
    }
}
var func = obj.getName(18);   //獲得閉包, getName中的this和arguments指向obj和 [Arguments] { '0': 18 }
var result = func(12, "多餘的引數");    //執行閉包  閉包中的this和arguments指向undefined(瀏覽器為window)和 [Arguments] { '0': 12, '1': '多餘的引數' } }
console.log(result);
/*console.log(obj.getName(18)(12, "多餘的引數"));*/    //這句和上面三句執行結果一樣

/*node環境下的返回值
{ th:Object [global] {...}     //注意這裡,谷歌瀏覽器返回的是window物件
  age: 18,
  na: undefined,     //谷歌瀏覽器是outer
  arg: [Arguments] { '0': 12, '1': '多餘的引數' } }*/

1)node環境下返回值截圖(上)

 

中間一堆node全域性環境。。

 

2)瀏覽器返回值截圖

 

 

4.2.5 相關面試題目

1 迴圈中使用閉包解決 var 定義函式的問題(答案:其應用裡面就是)

2

4.2.6 總結

 

百里於2020年7月20日

如果有錯,請您指出!如有侵權,請聯絡我刪除!

相關文章