簡單示例理解神閉包

閉包,一個近乎神話的概念,對於那些有一點javascript使用經驗但從未真正理解閉包概念的人來講,理解閉包能夠看作是某種意義上的重生,可是須要付出很是多的努力才能理解這個概念,今天咱們經過簡單示例來理解一下神閉包。
// 最簡單的閉包示例
function foo(){
    var a = 2;

    function bar(){
        console.log(a);
    }

    return bar;
}

var baz = foo();
baz(); // 2   ----朋友,這就是閉包效果

// 傳遞函數的閉包效果
function foo(){
    var a = 2;

    function baz(){
        console.log(a);
    }

    bar(baz);
}

function bar(fn){
    fn();     // 媽呀快看啊,這就是閉包效果
}

// 傳遞函數固然也能夠是間接的
var fn;

function foo(){
    var a = 2;

    function baz(){
        console.log(a);
    }

    fn = baz;
}

function bar(){
    fn();   // 媽呀快看啊,這就是閉包效果
}

foo();

bar(); // 2

// 到處都是閉包,延時器方法來演示閉包
function wait(message){

    setTimeout(function timer(){
        console.log(message);
    }, 1000);
}

wait("hello,closure!");

//將一個內部函數(名爲timer)傳遞給setTimeout(..)。timer具備涵蓋wait(..)做用域的閉包。所以還保有對變量message的引用。
//wait(..)執行1000毫秒後,它的內部做用域並不會消失,timer函數依然保有wait(..)做用域的閉包。
//深刻到引擎的內部原理中,內置的工具函數setTimeout(..)持有對一個參數的引用,這個參數也許叫作fn或者func,或者其餘相似的名字。
//引擎會調用這個函數,在例子中就是內部的timer函數,而詞法做用域在這個過程當中保持完整。
//這就是閉包。

// 循環和閉包
// 要說明閉包,for循環是最多見的例子。
for(var i=1;i<=5;i++){
    setTimeout(function timer(){
        console.log(i);
    }, i*1000);
}

// 正常狀況下,咱們對這段代碼行爲的預期是分別輸出數字1~5,每秒一次,每次一個。
// 但實際上,這段代碼在運行時會以每秒一次的頻率輸出五次6.

// 仔細想一想緣由,關鍵在於延遲函數的回調會在循環結束時才執行,而當循環結束後,i的值已經變爲了6
// 咱們能夠看看最終運行的順序是下面這樣的
setTimeout(function timer(){
    console.log(6);
}, 1*1000);
setTimeout(function timer(){
    console.log(6);
}, 2*1000);
setTimeout(function timer(){
    console.log(6);
}, 3*1000);
setTimeout(function timer(){
    console.log(6);
}, 4*1000);
setTimeout(function timer(){
    console.log(6);
}, 5*1000);

// 想要實現咱們要的效果,實際上須要給回調函數一個獨立的i的副本,這樣i的值變化,就不會影響回調函數執行中得副本值了
for(var i=1;i<=5;i++){
    (function(){
        var j = i;
        setTimeout(function timer(){
            console.log(j);
        }, j*1000);
    })();
}

// 或者以下寫法也能夠
for(var i=1;i<=5;i++){
    (function(j){
        setTimeout(function timer(){
            console.log(j);
        }, j*1000);
    })(i);
}

// 重返塊做用域,let關鍵字能夠實現,但由於目前對瀏覽器的支持不夠,支持javascript1.8版本以上的瀏覽器才能夠,因此咱們建議非特殊狀況,不使用這個關鍵字
for(var i=1;i<=5;i++){
    let j=i;
    setTimeout(function timer(){
        console.log(j);
    }, j*1000);
}
//或者更簡單寫法
for(let i=1;i<=5;i++){
    setTimeout(function timer(){
        console.log(i);
    }, i*1000);
}

//正確的效果的運行順序以下:
setTimeout(function timer(){
    console.log(1);
}, 1*1000);
setTimeout(function timer(){
    console.log(2);
}, 2*1000);
setTimeout(function timer(){
    console.log(3);
}, 3*1000);
setTimeout(function timer(){
    console.log(4);
}, 4*1000);
setTimeout(function timer(){
    console.log(5);
}, 5*1000);

  

經過這幾個簡單示例,對閉包有了初步瞭解,閉包到處都在,在意咱們如何觀察和理解
更多信息能夠看看個人博文,並下載相關資料
相關文章
相關標籤/搜索