js中閉包這個概念對於初學js的同學來說, 會比較陌生, 有些難以理解, 理解起來非常模糊. 今天就和大家一起來探討一下這個玩意.
相信大家在看完后, 心中的迷惑會迎然而解.
閉包概念:
閉包就是有權訪問另一個函數作用域中變量的函數.
分析這句話:
1.閉包是定義在函數中的函數.
2.閉包能訪問包含函數的變量.
3.即使包含函數執行完了, 被閉包引用的變量也得不到釋放.
例子分析-1: function add(){ var i = 0 arr = []; for(; i < 10; i++){ arr.push(function(){ alert(i); }); } return arr; } var temp = add(); temp[0](); 大家猜猜這個結果是多少? 0, i, 10? 我想大家會說是0. 但是結果是10. 我想大家想的應該是這樣滴: i = 0, arr.push(function(){ alert(0); }) i = 1, arr.push(function(){ alert(1); }) ... i = 10, arr.push(function(){ alert(10); }) 咋一看, 這個確實合理, 根據閉包的定義, 具體這個當然是上面分析的那樣了. 問題就出在這個變量的理解上. 1.i是變量不假, 但是i在for循環的時候, 一直在不斷變化. 也就是說這個i在參與for循環的時候, 值是不確定的, 等到for執行完后, i的值才確定. 2.每次push一個匿名函數表達式時, 那只是定義一個函數, 並沒去執行那個函數, 所以那個函數里引用的外部變量都是原封不動的放進去的. 換句話說, 就是這個匿名函數在最后執行的時候, 才會去查找作用域鏈, 直至找到那個變量i為止. 也就是: i = 0, arr.push(function(){ alert(i); }) i = 1, arr.push(function(){ alert(i); }) ... i = 10, arr.push(function(){ alert(i); }) 執行add()時, i參與循環完畢, i = 10. 執行temp[0]()時, 匿名函數會查找i, 先看自己, 我的i有值嗎?沒有. 再找他的上級函數, i有值嗎?有, i = 10. 查找結束. 至此, 不管執行temp[0](), 還是temp[5](), 還是temp[10](), 結果都是10. 改一下上面的例子, 讓它符合我們的預期要求. 例子分析-2: function add(){ var i = 0 arr = []; for(; i < 10; i++){ arr.push( (function(n){ return function(){ alert(n); } })(i)//注意這個變化
); } return arr; } var temp = add(); temp[0](); temp[1](); ... 這次結果是預期的,結果是 0 , 1 , 2, 3 ... 10 分析一下循環那部分. (function(n){ return function(){ alert(n); } })(i)
這個叫做立即執行的匿名函數表達式(不清楚這種寫法的, 可以先google下, 或者看我的單獨一篇專門介紹) i這個是時候就被當做參數傳遞了, 每次這個匿名函數執行時, i都會把自己的值復制一份給n return語句中的匿名函數引用着n, 此時已經和i無關了. 每次匿名函數表達式執行時, 都會保存一個不同的n. return語句中的匿名函數每次也引用着不同的n。 形象點就是這樣: arr.push( (function(n = i = 0){ return function(){ alert(n = 0); } })(i = 0) ) arr.push( (function(n = i = 1){ return function(){ alert(n = 1); } })(i = 1) )
...
閉包的介紹就到此為止了.