JavaScript 閉包

雲崖先生 發表於 2020-08-01

JavaScript 閉包

作用域

  在Js中,所有的名字(變數/常量/函式/類)都有一個作用範圍,這被稱之為作用域。

 

全域性作用域


  全域性作用域即是在全域性下定義的名字作用範圍,在Js中全域性作用域中的名字全域性有效,在任何作用域中都能進行訪問。

 

  生命週期:頁面開啟則產生,頁面完畢時銷燬

  數量:最多隻有一個

 

image-20200731233734502

 

區域性作用域


  區域性作用域通常是指在函式中定義的名字作用範圍,區域性有效,外部不能訪問。

 

  生命週期:對於函式的區域性作用域來說,函式呼叫時存活,呼叫完畢則銷燬,也就是說每次呼叫函式都會新增一個區域性作用域。函式執行完畢後該作用域將不復存在。

  數量:可以有多個區域性作用域

 

image-20200731234314517

 

塊級作用域


  塊級作用域的範圍小了很多,它只包含在{}中由let/const定義的名字的作用範圍,也是區域性有效,外部不能訪問。

 

  生命週期:塊級作用域是可以有多個的,生命週期為當執行塊級作用域中程式碼塊時塊級作用域存活,執行完畢後塊級作用域銷燬。

  數量:可以有多個塊級作用域

 

image-20200731235222291

 

名字查詢順序


  先到自身的作用域中查詢,如果沒有再到定義自己作用域的作用域中進行查詢。

 

image-20200731235914695

 

<script>"use strict";
​
        let username = "雲崖";
​
        let age = 18;
​
        function show() {
​
​
                let username = "Yunya";  // 如果這裡註釋掉下面的查詢結果是雲崖
​
                let age = 16;
​
                console.log("show...");
​
                (function () {
​
                        console.log(username);  // Yunya
​
                }());
​
        }
​
        show();
​
​
</script>

 

塊級作用域的封裝


  在之前沒有塊級作用域這一概念之前進行模組封裝都是使用自執行函式利用它函式區域性作用域的特性進行封裝,但是現在有了let/const塊級作用域後我們又有了新的封裝方式。

 

  封裝

{
​
        let show = function () {
                console.log("執行了show功能");
        }
​
        let test = function () {
                console.log("執行了test功能");
        }
​
        window.module = { show, test };
​
};

 

  呼叫

<script src="JavaScript.js"></script> 
<script>// 注意上面要引入模組
    
        "use strict";
​
        module.show();
        module.test();
​
</script>

 

閉包

  閉包其實非常簡單,它是基於函式巢狀+作用域+函式引數進行實現的。

 

  閉:一個封閉的函式,不能被外部直接呼叫,所以該函式肯定是在一個區域性作用域或塊級作用域中。

  包:一個包裹閉函式的函式被稱之為包函式。

 

  我們一定要注意一件事,即區域性作用域的銷燬是在函式執行完後進行銷燬,但是這個銷燬時機是有講究的。

  如果我們將區域性作用域中的一個名字返回出去,那麼該區域性作用域的銷燬時機是什麼呢?這個得看情況。

 

  該名字指向的是一個值型別:立即銷燬!值型別直接複製值就好了。

  該名字指向的是一個引用型別:不銷燬!引用型別可能會被引用,你把區域性作用域銷燬了那塊記憶體地址就空了,引用型別還引用個毛線。

 

<script>"use strict";
​
        function outer(){
​
                let username = "雲崖";
​
                // 由於返回的是一個引用物件,故outer的作用域環境不會被銷燬,如果銷燬了記憶體地址清空就找不到這個
                // 函式了,由於outer的作用域環境不會銷燬那麼username也將會存活。
return function(){ 
​
                        console.log(username);  // 自己找不到,去上層找唄。然後找到了 雲崖 
​
                }
​
        }
​
        let func = outer(); // func就是返回出來的匿名函式
        func();
​
</script>

 

閉包注意事項

  少用,少用。

  不銷燬區域性作用域代表不銷燬這一塊的記憶體,因此每做一個閉包函式一旦呼叫就會多出一塊跟隨全域性作用域銷燬的區域性作用域,如果呼叫多了這個閉包函式那就emmm....