在工作中在很多情況下都會用到閉包,但是當別人問起閉包到底是什麼時,總是覺得說不出個所以然來,所以這次準備把閉包這個知識點好好的梳理一遍,以加深對閉包的理解。而且很多時候我們也容易將匿名函式跟閉包弄混,所以在此區分一下。寫得不對的地方歡迎各位大神指出。
1、什麼是閉包?
含義: 有權訪問另一個函式作用域中的變數的函式。
建立方式: 在一個函式內建立另一個函式。
目的: 主要是為了設計私有的方法和變數。
優點: 可以避免全域性變數的汙染。
缺點: 1、閉包會常駐記憶體,會增大記憶體使用量,使用不當很容易造成記憶體洩露。2、閉包只能取得包含函式中任何變數的最後一個值。
特性:
1.函式巢狀函式;
2.函式內部可以引用外部的引數和變數;
3.引數和變數不會被垃圾回收機制回收; 4.在執行環境中,閉包的作用域包含著它自己的作用域、包含函式的作用域和全域性作用域; 5.當函式返回了一個閉包時,這個函式中的作用域將會一直儲存到閉包不存在為止。 閉包例子1:
function test(){
var x=10;
function foo(){
x*=2;
return x;
}
return foo;
}
//或者
function test(){
var x=10;
return function(){
x*=2;
return x;
};
}
var y=test();
for(var i=0;i<4;i++){
console.log(y());//20、40、80、160
}
複製程式碼
結果分析:上述程式碼是一個閉包。我們在test()函式後,返回了一個指向函式foo物件的指標——foo(函式是物件,函式名實際上是一個指向函式物件的指標)。所以此時變數y其實就是一個指向函式foo物件的指標。但我們呼叫y()也就是在呼叫foo(),在函式foo()內,變數x可以看成是相對foo()函式的全域性變數。所以每次呼叫foo()函式後,函式內的X物件的記憶體不會被銷燬,所以會出現每次呼叫y()的結果是前面的兩倍。
閉包例子2:
function createFunctions() {
var result = new Array();
for(var i = 0; i < 10; i++) {
result[i] = function() {
return i;
};
}
return result;
}
var result=createFunctions();
for(var i=0;i<result.length;i++){
console.log(result[i]());/10個10
}
複製程式碼
結果分析:result是一個儲存10個函式的陣列。根據閉包的特性可知,i可以看成是resulti函式的全域性變數。所以迴圈10次後,i變成了10(最後一次i++等於10,迴圈條件不成立,但i作為一個相對全域性變數,在result[i]中的值最後都是10)。
閉包例子3:
function handler(){
var dom=document.getElementById("test");
dom.onclick=functin(){
process(dom.id);
}
}
//推薦
function handler(){
var dom=document.getElementById("test");
var id=dom.id
dom.onclick=functin(){
process(id);
}
dom=null;
}
複製程式碼
分析:上面
2、什麼是匿名函式?
顧名思義,匿名函式就是沒有名稱的函式,由編譯器指定名稱並分配空間,通常直接作為引數傳遞。
匿名函式的形式如下:
//形式1 函式表示式
var test=function(){
return 20;
}
//形式2 立即執行函式
(function(i){
rentun i
})(5);
形式2可以變成如下:
var =testfunction(i){
return i;
}
test(5);
複製程式碼
立即執行函式的模式是為了保護函式體中的資料不被外界訪問,以免被外界環境汙染,同時還不會在記憶體中留下對該函式的引用。
不同點: 匿名函式是指沒有指定函式名稱的函式,而閉包有權訪問另一個函式作用域中的變數的函式。有時候在閉包中使用匿名函式。
相同點: 他們都可以設計私有的方法和變數(如立即執行函式)、都可以避免全域性變數的汙染。