好程序員web前端教程分享js閉包爲了更好的理解閉包,從網上搜羅了很多資料,集各家之精華(自認爲),拼拼湊湊自己總結了一下。
## 閉包
閉包是一個能讀取其他函數內部變量的函數:
1. 閉包是一個函數
2. 這個函數能讀取到其他函數內部的變量(局部變量)
3. 他能讓讀取到的變量始終保存在內存中
## 閉包的缺陷:
閉包函數讀取到的變量會一直保存在內存中,不做處理地盲目使用很容易有內存泄漏(內存未釋放或無法釋放所造成的內存浪費,導致程序運行速度減慢)的風險
## 案例
說了一堆,來點乾貨
這個是從網上看到的一個案例
```
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);
```
當時我把代碼粘過來,邊看程序邊分析,把每一塊分析的過程都寫了下來
```
function fun(n, o) {
console.log(o);
return { // 這裏返回一個對象,對象有個fun函數
fun: function (m) { // 函數返回 調用fun 函數的返回值
return fun(m, n);
}
};
}
var a = fun(0); // ? 傳參時只傳了0,所以n是0,o爲 undefined;a即爲fun返回的對象
// a.fun() 就是閉包函數,var a = fun(0)中的 n=0,o=undefined 都會常駐在內存中
a.fun(1); // ? 重新調用fun(n, 0),m = 1,n = 0,console.log(o),結果爲0
a.fun(2); // ? 0
a.fun(3); // ? 0
var b = fun(0).fun(1).fun(2).fun(3); // ? 0 1 2
// 1. fun(0)爲對象,此時的n = 0,o = undefined,輸出 undefined
// 2. 然後調用對象的fun(m),m = 1,返回值爲調用外部fun(n, o)的返回值,n = 1, o = 0 而這個返回值又是一個對象,輸出0
// 3. 然後又調用對象的fun(m),m = 2,返回值爲調用外部fun(n, o)的返回值,n = 2, o = 1 而這個返回值又是一個對象,輸出1
// 4. 然後又調用對象的fun(m),m = 3,返回值爲調用外部fun(n, o)的返回值,n = 3, o = 2 而這個返回值又是一個對象,輸出2
// 這裏指的注意的是每次的n和o的值都不一樣,是因爲他們分別在不同的函數作用域內,這裏每次都調用了一個新的fun(),開闢了一塊新空間
var c = fun(0).fun(1); // ? undefined,0
// 而這裏兩次的結果都是1,因爲他們都是通過c這個對象調用的,就是說因爲他們都在同一個函數作用域內
c.fun(2); // ? 1
c.fun(3); // ? 1
```
分析的過程簡直是一場頭腦風暴,稍不留神就會跑偏,總算寫完之後趕緊去對照他的答案(當時並沒有跑一遍程序),結果發現`var b = fun(0).fun(1).fun(2).fun(3);`這裏答案不一樣,他給的答案是`undefined, 0, 0, 0`,而我得到的結果是`undefined, 0, 1, 2`,我就又回頭看了一遍,覺得自己分析的沒問題啊,這時候突然想到我還沒跑一遍試試,於是抓緊跑一波,結果果然是站在我這邊的:
![閉包.png](http://upload-images.jianshu.io/upload_images/3629578-a24ad6153de774ef.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
果然,寫程序就是得自信點