循環和閉包

工做中大量的使用javascript,可是卻並理解閉包是什麼?總感受這門語言有其隱蔽的一面,若是可以掌握將會千米大增。javascript

閉包是基於詞法做用域書寫代碼時產生的天然結果,其實閉包在日常書寫的js代碼中隨處可見。java

當函數能夠記住並訪問所在的詞法做用域時,就產生了閉包,即便函數是在當前詞法做用域以外執行閉包

PS:我對其的理解是當一段詞法做用域的代碼執行以後,js引擎會對其進行回收,以便來提升性能,可是閉包阻止了這種回收,使這段詞法做用域依舊處在內存當中,當你調用詞法做用域中的局部變量時,依舊存在。函數

下面咱們來看一段代碼,清晰地展現了閉包:性能

function foo(){spa

    var a = 2;ip

    function bar(){內存

        console.log(a);作用域

    }回調函數

    return bar;

}

var baz = foo();

baz(); //2  ----這就是閉包的效果

在 foo() 執行後,一般會期待 foo() 的整個內部做用域都被銷燬,由於咱們知道引擎有垃圾回收器用來釋放再也不使用的內存空間。因爲看上去 foo() 的內容不會再被使用,因此很 天然地會考慮對其進行回收。 而閉包的「神奇」之處正是能夠阻止這件事情的發生。事實上內部做用域依然存在,所以 沒有被回收。

function wait(message) {

    setTimeout( function timer() {

        console.log( message );

    }, 1000 );

}

wait( "Hello, closure!" );

wait(..) 執行 1000 毫秒後,它的內部做用域並不會消失,timer 函數依然保有 wait(..) 做用域的閉包。

要說明閉包,for 循環是最多見的例子。

for (var i=1; i<=5; i++) {

     setTimeout( function timer() { console.log( i );

    }, i*1000 );

}

正常狀況下,咱們對這段代碼行爲的預期是分別輸出數字 1~5,每秒一次,每次一個。

但實際上,這段代碼在運行時會以每秒一次的頻率輸出五次 6。

事實上, 當定時器運行時即便每一個迭代中執行的是 setTimeout(.., 0),全部的回調函數依然是在循 環結束後纔會被執行,所以會每次輸出一個 6 出來。

正確的作法是,咱們要使用閉包,首先按照定義咱們要給每次循環一個詞法做用域,每一個做用域都要有本身的i的值,以下:

for(var i =1; i<=5;i++){

    (function(i){ //給每次循環一個獨立的詞法做用域

        setTimeout(function(){

            console.log(i);

        },i*1000);

    })(i);

}

固然在ES6中,能夠用let聲明:

for (let i=1; i<=5; i++) {

     setTimeout( function timer() {

        console.log( i );

    }, i*1000 );

}

相關文章
相關標籤/搜索