##閉包
###什麼是閉包 這幾天在一直在研究js的閉包,算是對它有自己的一點點理解,首先維基百科是這樣說的
在計算機科學中,閉包(Closure)是詞法閉包(Lexical Closure)的簡稱,是引用了自由變量的函數。這個被引用的自由變量將和這個函數一同存在,即使已經離開了創造它的環境也不例外。所以,有另一種說法認爲閉包是由函數和與其相關的引用環境組合而成的實體。
Peter J. Landin 在1964年將術語閉包定義爲一種包含環境成分和控制成分的實體。
有點複雜,我們用最簡單的代碼來說一下
function x() {
var tmp = 1;
function a(){
console.log(tmp++);
}
a();
}
x();
x();
x();
我們定義了一個函數x,裏面有一個變量tmp,又有一個內部函數a(),並且最後執行了這個a(),我們執行這個x三次。發現都打印出來都是1,這種用法雖然很奇怪,但是結果我們是可以理解的,很簡單,但是如果我們把a返回,在外部執行呢
function x() {
var tmp = 1;
function a(){
console.log(tmp++);
}
return a;
}
var b = x();
b(); //1
b(); //2
b(); //3
首先我們定義了一個函數,裏面有一個變量,一個函數(直接返回了),這個x我們稱爲外部函數,裏面返回的我們成爲內部函數,tmp我們稱爲外部函數的變量,外部變量,然後我們調用x,返回的函數,我們賦值給b,接下來,我們調用b,三次,第一次,結果爲1,第二次第三次結果是2和3。 是不是覺得有點神奇,這個tmp是我們在內部定義的,正常來說,我們調用了x以後,我們就無法訪問到tmp的了,但是我們現在發現這個tmp並沒有被銷燬,而且我們外部可以訪問對並且對其進行了操作,其實這個 b就是一個閉包
那麼,要怎麼形成這個閉包呢
- 在一個函數的內部定義了一個函數(x裏面定義了a)
- 這個函數引用了一個外部的變量(在內部函數a裏面引用了外部函數的tmp)
- 並且把這個函數返回了
只有滿足了這三個條件,就是一個閉包
###閉包對於外部的值的使用是引用 閉包在實際調用的時候,纔去找到該值的實際值,而不是在定義的時候的值,這個要怎麼理解呢,還是上代碼
function createFunctions() {
var result = new Array();
for (var i = 0; i < 10; i++) {
result[i] = function() {
return i;
};
}
return result;
}
var a = createFunctions();
var test1 = a[0]();
var test2 = a[1]();
console.log(test1); //10
console.log(test2); //10
這裏我們定義了一個函數createFunctions,在裏面循環10次,創建了10個函數,賦給了result,最後把result返回。我們調用這個函數,吧返回值給a,這個時候a就是一個擁有10個函數的一個數組,我們調用其中兩個,發現打印出來的結果都是10,爲什麼呢,如果i都是10,那麼在循環的時候是怎麼可以循環成功的,這就是我上面說的,閉包裏面的內部函數,對於外部值的使用,都是引用,也就是result[i]這裏的i是在定義的時候已經確定了值,0-9,而內部的i只是一個引用,需要我們在實際調用的時候a[0]和a[1]的時候,再去找這個i的值,這個時候i因爲是閉包裏面的變量,在循環完以後並沒有銷燬,還保存在了閉包裏面,值爲10。
那麼利用閉包的特效,我們可以做什麼事情呢,首先,因爲它一直在內存中的特性,我們可以用它來做計算器。
function count(num) {
return function() {
return num++;
}
}
a = count(0);
console.log(a()); //0
console.log(a()); //1
console.log(a()); //2
console.log(a()); //3
這是比較簡單的應用,還有一些比較高級點的,可以看看我的 github