1. 程式人生 > >JavaScript---設計模式與開發實踐--第三章 閉包

JavaScript---設計模式與開發實踐--第三章 閉包

JavaScript—設計模式與開發實踐–第三章 閉包

  • 閉包(closure)是Javascript語言的一個難點,也是它的特色,很多高階應用都要依靠閉包實現。
  • 對於 JavaScript程式設計師來說,閉包(closure)是一個難懂又必須征服的概念。

閉包是指有權訪問另一個 函式作用域中的變數的函式 ----> 《JavaScript高階程式設計》第三版

閉包就是能夠讀取其他函式內部變數的函式 ------阮一峰

  • 這兩種解釋都是易於理解的。我覺得阮一峰關於閉包的解釋比較好。

總結《JavaScript—設計模式與開發實踐》閉包

閉包

閉包的形成與變數的作用域以及變數的生存週期

密切相關

變數的作用域

變數的作用域,指的是變數的有效範圍。執行環境型別只有兩種全域性和區域性(函式)。在函式中宣告的變數就是區域性變數,只有在該函式內才能訪問這個變數。

        var func = function(){
           var a = 1;
           alert(a); // 1
       }
       func();
       alert(a); // a is not defined

在JS中,函式可以創造函式作用域,就好像: 此時的函式是一層半透明的玻璃,在函式裡面可以看到外面的變數,而在函式外面無法看到看到函式裡面的變數。

  • 變數搜尋過程:在函式中搜索一個變數的時候,如果該函式內沒有宣告這個變數,那麼此次搜尋過程會隨著程式碼執行建立的作用域鏈往外層逐層搜尋,一直到全域性物件為止。
  • 變數的搜尋時從內而外而非從外到內的。
        var a = 1;
      var func1 = () => {
          var b = 2 ;
          var func2 = () => {
              var c = 3;
              alert(b);  //2
              alert(a); //1
          }
          func2();
          alert(c);  // c is not defined
      }
      func1();

變數的生存週期

除了變數的作用域之外,另外一個跟閉包有關的概念是變數的生存週期。

  • 對於全域性變數來說,全域性變數的生存週期是永久的,除非我們主動銷燬這個全域性變數。
  • 而對於在函式內用var 關鍵字宣告的變數來說,當退出函式時,這些區域性變數失去了他們的價值,他們會隨著函式呼叫的結束而被銷燬
    var func = function(){
        var a = 1;
        alert(a);
    };
    func():

退出函式(函式執行完)後區域性變數a就會被銷燬。 下面這個例子:

    var func = function(){
        var a = 1;
        return function(){
            a++;
            alert(a);
        }
    }
    var f = func();
    f();    //2
    f();    //3
    f();    //4
    f();    //5
  • 這裡就產生了一個閉包結構。 當退出函式後,區域性變數a並沒有消失,而是一直在某個地方存活著;
  • 因為當執行var f = func() 時,f 返回的時匿名函式的引用,它可以訪問到func()被呼叫時產生的環境,而區域性變數a一直在這個環境裡。既然區域性變數所在的環境還能被外界訪問,這個區域性變數就有了不被銷燬的理由。這就是一個閉包結構,區域性變數的宣告看起來被延續了。

閉包的作用(場景)

  • 封裝"私有"變數 閉包可以幫助把一些不需要暴露在全域性的變數封裝成“私有變數“
            function Person() {
			var name = "asd";
			var sex = "man";
			// 這個變數是私有的變數。
			var yinsi = "....";

			return function() {
				// key: value
				var obj = {
					name: name,
					sex: sex
				}
				return obj;
			}
		}
		console.log(Person()().name);

閉包面向物件設計

下面這段程式碼對理解面向物件設計有很大的幫助。

    var extent = function(){
        var value = 0;
        return {
            call:function(){
                value++;
                console.log(value);
            }
        }
    };
    var e = extent();
    e.call();
    e.call();
    e.call();

把這段程式碼換成面向物件的寫法

    var extent = {
        value : 0,
        calc  : function(){
            this.value++;
            console.log(this.value);
        }
    };
    extent.calc();
    extent.calc();
    extent.calc();