javascript閉包,你大爺永遠是你大爺

閉包 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時說,閉包,在其餘語言中,有的有,有的沒有


通常來講,一個函數在執行開始的時候,會給其中定義的變量劃份內存空間保存,以備後面的語句所用,等到函數執行完畢返回了,這些變量就被認爲是無用的了.對應的內存空間也就被回收了.下次再執行此函數的時候,全部的變量又回到最初的狀態,從新賦值使用.

可是若是這個函數內部又嵌套了另外一個函數,而這個函數是有可能在外部被調用到的.而且這個內部函數又使用了外部函數的某些變量的話.這種內存回收機制就會出現問題.若是在外部函數返回後,又直接調用了內部函數,那麼內部函數就沒法讀取到他所須要的外部函數中變量的值了.因此js解釋器在遇到函數定義的時候,會自動把函數和他可能使用的變量(包括本地變量和父級和祖先級函數的變量(自由變量))一塊兒保存起來.也就是構建一個閉包,這些變量將不會被內存回收器所回收,只有當內部的函數不可能被調用之後(例如被刪除了,或者沒有了指針),纔會銷燬這個閉包,而沒有任何一個閉包引用的變量纔會被下一次內存回收啓動時所回收.


這一段,便是原理,也是實現,(更是核心關鍵,理解了這個,就理解了閉包。)


用大白話,第一人稱的說話法是,我函數是大爺,我函數在定義時,所用的變量,你必須都給我找地方存好了,就存一份就行,爺兒我被調用的時候,就要用這些變量!記作:你大爺永遠是你大爺!補充:存的並非這個變量聲明之時的快照,而是這些變量,在閉包函數執行時,變量中所存的真實值


函數的參數,在這個函數每次被調用之時,參數也是開出一個內存空間去存的


看個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

用閉包,就搞定了


前端開發必須知道的JS(二) 閉包及應用

www.cnblogs.com/ljchow/arch…


PS : 沸水理論,簡版,一壺水,只有燒到100度才能去喝,你每次都只燒到80度就不燒了,那麼你永遠也喝不上這水,學習也是同樣,快要學透閉包了,就停下來不學,那麼永遠也不可能真正撐握閉包,不可能在工做中,爲所欲爲的去使用閉包。


學到此,你應該已是沸水100度了!


寫的很差,請你們多批評:)

相關文章
相關標籤/搜索