閉包 what 's the fuckjavascript
閉包,是什麼鬼,誰學誰都腦進水!html
我會用5W3H1TS的方式,去講閉包前端
1. whatjava
一個函數,記住本身定義時的「詞法做用域」,就產生了閉包安全
即便此函數在其餘地方執行!閉包
上一個「詞法做用域」的 例子 ,程序走起,與JAVA的動態做用域,有本質不一樣框架
因果鏈思惟中,這個詞法做用域就是「已知的由於」,經過這個由於,咱們往下想,才能想通,閉包這個結果函數
例子:學習
var fn1;
function aa(){
var t1 = 100;
fn1 = function(){
console.log(t1);
}
}
var t1 = 200;
aa();
fn1();
複製代碼
結果是打印 100,ui
結論: 能夠肯定,JS真的是詞法做用域
我是按「例子-結論」的思惟去作的
2. why
閉包是解決函數式語言的一個問題的一種技術,這個問題就是如何保證將函數當作值創造並傳來傳去的時候函數仍能正確運行。
閉包實現的例子,其中一種用法: 模擬塊做用域,不要全局污染。由於JS只有全局做用域和函數做用域(這話並不徹底對,但先記住,這就是JS讓人FUCK的緣由。。。,不像JAVA,很是規矩,讓學的人,學起來也能很是清楚,省力)
3. who
JS有的,咱們這裏只討論JS的範疇,宿主環境,JS的引擎。其餘語言,有的有,有的沒有
4.where
框架中,還有當即執行函數中,JQUERY庫,JQ寫的小組件
5. when
看下面連接的文章
6. how1
具體用時,要寫什麼,先上一個小例子
例子:
var result = foo(1)(2);
alert(result);
function foo(a){
return function(b){
return a+b;
}
}
複製代碼
很簡單,結果爲3
再上一個有應用場景的小例子
<html> <title>小例子</title> <meta http-equiv="Content-Type" content="text/html" ; charset="utf-8"> <body onload="myEffect()"> <table id="mytab" border="1"> <tr> <td> 第0行 </td> </tr> <tr> <td> 第1行 </td> </tr> <tr> <td> 第2行 </td> </tr> </table> <div id="console" style="background:#ffff00"></div> </body> <script> function myEffect(){ var console=document.getElementById('console'); var tab=document.getElementById('mytab'); var trs=tab.getElementsByTagName('tr'); for(var i=0;i<trs.length;i++){ trs[i].onclick=(function(){ var rowNum=i; return function(){ console.innerHTML="點擊了第"+rowNum+"行"; } })(); } } </script> </html> 複製代碼
試試,不去用 var rowNum=i;
而是改成:
trs[i].onclick=(function(){
return function(){
console.innerHTML="點擊了第"++"行";
}
})();
複製代碼
會發生神馬,而後自行體會一下,再往下看
7.how2
實現原理
函數調用是用棧,存變量是用堆(不必定正確,只是比喻,爲了方便理解),
函數被調用時,函數
與內存GC機制相關,因此3時說,閉包,在其餘語言中,有的有,有的沒有
這一段,便是原理,也是實現,(更是核心關鍵,理解了這個,就理解了閉包。)
函數的參數,在這個函數每次被調用之時,參數也是開出一個內存空間去存的
看個TIME的例子,也是核心例子了!
for(var i = 0; i < 5; i++) {
setTimeout(function() {
console.log(i);
}, 1); //1毫秒後,打印
}
複製代碼
這個代碼,本意是想 打印
0
1
2
3
4
可是,打出來是
5
5
5
5
5
當你知道「你大爺永遠是你大爺」的理論後,就會明白,
function() {
console.log(i);
}
複製代碼
此函數,所用的i這個變量,是存了一份,找地方放好了,可是這個變量i,他的值卻也在變化,因此當此函數用這個變量時,這個變量的值,就變爲5了!
要想達到輸出,0到4的結果,就要讓變量存上一份,而且沒有其餘程序去改變他,就OK了
下面,提供四個改法,都是用了上面的理論,你們再體會一下
for(var i = 0; i < 5; i++) {
setTimeout((function(ii) {
return function(){
console.log(ii);
}
})(i), 1);
}
複製代碼
這是setTimeout內部的函數,去閉包存一份不變的變量法,還能夠不用參數去存一份單獨的變量
for(var i = 0; i < 5; i++) {
setTimeout((function() {
var ii = i;
return function(){
console.log(ii);
}
})(), 1);
}
複製代碼
咱們再來,把單存的變量,放到setTimeout以外
for(var i = 0; i < 5; i++) {
(function(ii) {
setTimeout(function () {
console.log(ii);
}, 1);
})(i);
}
複製代碼
同理,也能夠不用參數:
for(var i = 0; i < 5; i++) {
(function() {
var ii = i;
setTimeout(function () {
console.log(ii);
}, 1);
})();
}
複製代碼
這就是四個例子,核心思想就是讓閉包的變量是單獨的,不要被別的代碼去改變值,這樣就能達到想要的目的了,其實就是在內存中建了5個變量,去存這0,1,2,3,4這5個變量的值,在須要的時候,取出來用。
8.tip
優勢:
1.保護函數內的變量安全,增強了封裝性
2.在內存中維持一個變量(用的太多就變成了缺點,佔內存)
缺點
閉包的缺點就是常駐內存,會增大內存使用量,內存浪費,使用不當很容易形成內存泄露,無效內存的產生
9.scene
爲了看 複雜的代碼時用,本身主動用得少,
藏於框架之中的有,交互響應,寫的函數中,傳的參數常量,就是閉包,但通常人就當黑盒子看,對使用框架的人來講,是透明的
id.onclick = function(){ alert(i); } 循環四次,打出來,都是4
用閉包,就搞定了
PS : 沸水理論,簡版,一壺水,只有燒到100度才能去喝,你每次都只燒到80度就不燒了,那麼你永遠也喝不上這水,學習也是同樣,快要學透閉包了,就停下來不學,那麼永遠也不可能真正撐握閉包,不可能在工做中,爲所欲爲的去使用閉包。
學到此,你應該已是沸水100度了!
寫的很差,請你們多批評:)