閉包(Closure)

閉包是JavaScript的一大難點,也是它的特點。利用閉包能夠實現許多高級應用。今天咱們就一塊兒來討論一下有關閉包的問題。閉包


一.閉包的概念

不少語言中都有閉包,概念也不盡相同。就JS閉包的概念也有好多種,下面一種我認爲是比較好理解也比較精確的一種。模塊化

閉包是指有權訪問另外一個函數做用域中的變量的函數。函數

這句話能夠分爲兩步來理解:
1)閉包是函數;
2)這個函數能夠訪問另外一個函數做用域中的變量。性能

等等,做用域又是什麼鬼。。。this

第二點翻譯一下就是能夠訪問另外一個函數內部定義的變量。下面再解釋什麼是做用域。翻譯

示例代碼:code

function outer() {
    var name = "Foolgry";
    
    function inner() {
        return name;
    }
}

從技術層面來講,上面的inner已是一個閉包了。
1)它是一個函數;
2)它能夠訪問outer內部定義的變量name
可是,大多數人習慣的閉包是下面這個樣子的:對象

示例代碼:ip

function outer() {
    var name = "Foolgry";
    
    function inner() {
        return name;
    }
    return inner;
}

var getName = outer(); 

getName(); // "Foolgry"

這個inner確定是閉包,它不只知足上面的兩個條件,還具有一個特徵:即便outer運行後被回收,它可以保證name在內存中繼續存在。
每一個人都有不一樣的理解,有的人認爲只有第二個例子纔算閉包,第一個例子不算。個人理解是均可以算作閉包。內存

閉包自己並不難理解,可貴是它和做用域this等問題放在一塊兒。
提及閉包,就不得不談一些基礎問題,好比:上面提到的做用域


二.做用域

JS中有兩種做用域,全局做用域和局部做用域。

示例代碼:

var name = "Bob",//全局做用域下定義的變量(全局變量)
    age = 99,
    sex = "female";
function object() {
    var name = "Foolgry"; //局部做用域下定義的變量(局部變量)
    
    alert(name); // "Foolgry"
    alert(age); // 99
    alert(sex); // undefined
    
    var sex = "male",
        job = "fe"
}
alert(name);  // "Foolgry"
alert(job); // error
  • object做用域中,name是局部變量,雖然全局環境中也定義了變量name,可是在局部做用域中,會優先訪問局部變量;
  • 若是訪問不到,才找全局變量,如age同樣;
  • sex爲何是undefined呢?由於JS中有一種機制叫作變量提高。這東西會把上面幾句話變成這樣:

    var sex;
      alert(sex);
      sex = "male";
  • 訪問job發生錯誤,是由於通常狀況下局部變量只能在其函數做用域內部訪問,這也是爲何須要閉包了。


三.閉包應用

閉包的應用有不少,這裏只列舉其中兩種:

  • 模塊化代碼,減小全局變量的污染
  • 私有成員的存在

四.閉包須要注意的問題

1)因爲閉包會使得函數中的變量都被保存在內存中,內存消耗很大,因此不能濫用閉包,不然會形成網頁的性能問題,在IE中可能致使內存泄露。解決方法是,在退出函數以前,將不使用的局部變量所有刪除。

2)閉包會在父函數外部,改變父函數內部變量的值。因此,若是你把父函數看成對象(object)使用,把閉包看成它的公用方法(Public Method),把內部變量看成它的私有屬性(private value),這時必定要當心,不要隨便改變父函數內部變量的值。


五.閉包經典例子

function fun(n,o) {
    console.log(o);
        return {
            fun:function(m) {
                return fun(m,n);
            }
        };
}
var a = fun(0); a.fun(1);  a.fun(2);  a.fun(3);  
var b = fun(0).fun(1).fun(2).fun(3);
var c = fun(0).fun(1);  c.fun(2);  c.fun(3);

問:三行a,b,c的輸出分別是什麼?

這個例子若是你能所有答對,那麼JS閉包就沒什麼問題了。

undefined,0,0,0
undefined,0,1,2
undefined,0,1,1

下一篇文章討論一下這題解法。

相關文章
相關標籤/搜索