JavaScript中的函數會造成閉包。 閉包是由函數以及建立該函數的詞法環境組合而成。這個環境包含了這個閉包建立時所能訪問的全部局部變量。(閉包就是可以讀取其餘函數內部變量的函數。在本質上,閉包就是將函數內部和函數外部鏈接起來的一座橋樑。)javascript
for (var i = 0; i < 5; i++) {
setTimeout(function() {
console.log(new Date, i);
}, 1000);
}
console.log(new Date, i);
/* 結果:第 1 個 5 直接輸出,1 秒以後,輸出 5 個 5 Tue Mar 26 2019 11:25:19 GMT+0800 (中國標準時間) 5 Tue Mar 26 2019 11:25:20 GMT+0800 (中國標準時間) 5 Tue Mar 26 2019 11:25:20 GMT+0800 (中國標準時間) 5 Tue Mar 26 2019 11:25:20 GMT+0800 (中國標準時間) 5 Tue Mar 26 2019 11:25:20 GMT+0800 (中國標準時間) 5 Tue Mar 26 2019 11:25:20 GMT+0800 (中國標準時間) 5 */
// 若是指望代碼的輸出變成:5 -> 0,1,2,3,4 改造方法
1. 方案1: 匿名函數
for (var i = 0; i < 5; i++) {
(function(j) { // j = i
setTimeout(function() {
console.log(new Date, j);
}, 1000);
})(i);
}
console.log(new Date, i);
2. 方案2: 塊級做用域
for (let i = 0; i < 5; i++) {
setTimeout(function() {
console.log(new Date, i);
}, 1000);
}
複製代碼
閉包會使得函數中的變量都被保存在內存中,內存消耗很大,因此不能濫用閉包,不然會形成網頁的性能問題,在IE中可能致使內存泄露。解決方法是,在退出函數以前,將不使用的局部變量所有刪除。html
在requireJS出現以前,實現模塊化編程主要經過IIFE,而在IIFE中常見的操做就是經過window.fn = fn來暴露接口,而這個fn就是閉包,而IIFE只是一個包含閉包的函數調用前端
(function(){
var a = 0;
function fn(){
console.log(a);
}
window.fn = fn;
})()
fn();
// 定義一:須要經過做用域鏈查找變量的函數就是閉包
var a = 2;
(function foo(){
console.log(a);//2
})();
// 定義二: 訪問上層函數的做用域的內層函數就是閉包
function foo(){
var a = 2;
function bar(){
console.log(a); // 2
}
bar();
}
foo();
// 定義三: 在函數聲明時的做用域之外的地方調用函數,須要經過將該函數做爲返回值或者做爲參數被傳遞
function foo(){
var a = 2;
function bar(){
console.log(a); //2
}
return bar;
}
foo()();
複製代碼