首頁 >web前端 >js教程 >Javascript學習筆記之 函數篇(三) : 閉包與引用_基礎知識

Javascript學習筆記之 函數篇(三) : 閉包與引用_基礎知識

WBOY
WBOY原創
2016-05-16 16:30:361359瀏覽

Javascript 中一個最重要的特性就是閉包的使用。因為閉包的使用,目前作用域總是可以存取外部的作用域。因為 Javascript 沒有區塊級作用域,只有函數作用域,所以閉包的使用與函數是緊密相關的。

模擬私有變數

複製程式碼 程式碼如下:

function Counter(start) {
    var count = start;
    return {
        increment: function() {
            count ;
        },
        get: function() {
            return count;
        }
    }
}
var foo = Counter(4);
foo.increment();
foo.get(); // 5

這裡 Counter 回傳兩個閉包:函數 increment 和 get。這兩個函數一直保持著對 Counter 作用域的訪問,因此它們能一直訪問到定義在 Counter 作用域的變數 count。

私有變數的工作機制

由於 Javascript 不可以對作用域賦值和引用,所以在上例中,是沒有辦法在外部直接存取內部私有變數 count。唯一的方法就是透過定義閉包來存取。

複製程式碼 程式碼如下:

var foo = new Counter(4);
foo.hack = function() {
    count = 1337;
};

上面的程式碼不會改變 Counter 作用域內的 count 變數值,因為 hack 沒有在 Counter 內定義。上面這段程式碼只會建立或覆蓋全域變數 count。

循環內的閉包

一個最容易犯的錯誤就是在循環內使用閉包。

複製程式碼 程式碼如下:

for(var i = 0; i     setTimeout(function() {
        console.log(i); 
    }, 1000);
}

上面這段程式碼不會輸出0到9,而是連續輸出10次10​​。
上面的匿名會一直保持一個變數 i 的引用。當呼叫 console.log 函數開始輸出時,這是循環已經結束,而變數 i 已經為10了。
為了避免上面的錯誤發生,我們需要在每次循環時為變數 i 值建立拷貝。

避免引用錯誤

為了複製迴圈中變數的值,最好的方式是在外層加上一個匿名的立刻執行函數。

複製程式碼 程式碼如下:

for(var i = 0; i     (function(e) {
        setTimeout(function() {
            console.log(e); 
        }, 1000);
    })(i);
}

這個外部的匿名函數接收循環變數 i 作為第一個參數,並將其值拷貝至它自己的參數 e。
外部的匿名函數將參數 e 再傳遞給 setTimeout,因此 setTimeout 有了指向參數 e 的參考。而這個參數 e 的值不會因為外在的循環改變而改變。

還有另一個方法可以達到相同的效果,就是在 setTimeout 內的匿名函數中再傳回一個匿名函數:

複製程式碼 程式碼如下:

for(var i = 0; i     setTimeout((function(e) {
        return function() {
            console.log(e);
        }
    })(i), 1000)
}

此外,透過 bind 方法也可以實現。

複製程式碼 程式碼如下:

for(var i = 0; i     setTimeout(console.log.bind(console, i), 1000);
}

文章最後我們來總結下:

(1)閉包是一種設計原則,它透過分析上下文,來簡化使用者的調用,讓使用者在不知曉的情況下,達到他的目的;
(2)網路上主流的對閉包剖析的文章其實是和閉包原則反向而馳的,如果需要知道閉包細節才能用好的話,這個閉包是設計失敗的;
(3)盡量少學習。

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn