什麼是閉包
MDN的解釋:閉包是函數和聲明該函數的詞法環境的組合。
簡單講,閉包就是指有權訪問另一個函數作用域中的變量的函數。
它由兩部分構成:函數,以及創建該函數的環境。環境由閉包創建時在作用域中的所有局部變量組成。
理解閉包的關鍵在於:外部函數調用之後其變量對象本應該被銷燬,但閉包的存在使我們仍然可以訪問外部函數的變量對象,這就是閉包的重要概念。
如何產生一個閉包函數
創建閉包最常見方式,就是在一個函數內部創建另一個函數。
function outer() {
let name = "hello"; // 閉包創建時所能訪問的局部變量
function sayHello() { // 閉包函數
alert(name);
}
return sayHello; // 返回閉包函數
}
let myFunc = outer();
myFunc();
閉包的作用域鏈包含著它自己的作用域,以及包含它的函數的作用域和全局作用域。
outer有了myFunc的引用,內存一直得不到釋放,咋辦呢?這樣的函數多了是不是會造成內存溢出?
手動釋放一下:
myFunc = null;
閉包的注意事項(如何防止內存洩漏)
通常,函數的作用域及其所有變量都會在函數執行結束後被銷燬。但是,在創建了一個閉包以後,這個函數的作用域就會一直保存到閉包不存在為止。
function makeAdder(x) {
return function(y) {
return x + y;
};
}
let add5 = makeAdder(5);
let add10 = makeAdder(10);
console.log(add5(2)); // 7
console.log(add10(2)); // 12
add5 = null;
add10 = null;
add5 和 add10 都是閉包。它們共享相同的函數定義,但是保存了不同的詞法環境。在 add5 的環境中,x 為 5。而在 add10 中,x 則為 10。
最後通過 null 釋放了 add5 和 add10 對閉包的引用。
在javascript中,如果一個對象不再被引用,那麼這個對象就會被垃圾回收機制回收;
如果兩個對象互相引用,而不再被第3者所引用,那麼這兩個互相引用的對象也會被回收。
閉包中的this對象
let name = "window";
let obj = {
name: 'object',
getName: function() {
return function() {
return this.name;
}
}
}
obj.getName()(); // window
在上面這段代碼中,obj.getName()()實際上是在全局作用域中調用了匿名函數,this指向了window。
window才是匿名函數功能執行的環境。
如果想使this指向外部函數的執行環境,可以這樣改寫:
let name = "window";
let obj = {
name: 'object',
getName: function() {
var that = this;
return function() {
return that.name;
}
}
}
obj.getName()();
函數內部的定時器
當函數內部的定時器引用了外部函數的變量對象時,該變量對象不會被銷燬。
(function() {
let a = 0;
setInterval(function(){
console.log(a++);
}, 1000)
})()
閉包的用途
- 模擬塊級作用域
var isShow = true;
if(isShow){
var a=1000;
console.log(a);
}
console.log(a); // 在if定義的變量在外部可以訪問
(function(){ // a在外部就不認識啦
var isShow = true;
if(isShow){
var a=10000;
console.log(a);
}
})();
console.log(a); // 報錯,無法訪問
- 讓變量的值始終保持在內存中,對結果進行緩存
function fn(){
let count = 0;
return function(){
count++;
return count;
}
}
let add=fn();
add(); // 1
add(); // 2
add(); // 3
- 封裝工具函數
let counter = (function(){
let privateCounter = 0; // 私有變量
function change(val){
privateCounter += val;
}
return {
increment:function(){ // 三個閉包共享一個詞法環境
change(1);
},
decrement:function(){
change(-1);
},
value:function(){
return privateCounter;
}
};
})();
counter.value(); // 0
counter.increment();
counter.value(); // 1
經典前端面試題每日更新,歡迎參與討論,地址:https://github.com/daily-interview/fe-interview。
更多angular1/2/4/5、ionic1/2/3、react、vue、微信小程序、nodejs等技術文章、視頻教程和開源項目,請關注微信公眾號——全棧弄潮兒。
閱讀更多 全棧弄潮兒 的文章
關鍵字: 淺談 JavaScript 閉包