懷着一顆忐忑的心來寫這篇文章,由於今天寫的是閉包,關於閉包的理解可能你們都很是理解了,也怕寫的很差,誤導了部分的初學者,但願下面內容有任何寫的很差的地方,歡迎你們積極的指出來,真正的進步就是你們共同進步。也可以讓本身成長起來,這也是我寫堅持寫博客的緣由之一。chrome
好了,廢話閒說,咱們進入咱們的正題:閉包瀏覽器
function Car () {
let wheel = 4;
function drive () {
console.log(wheel + ' wheel run');
}
return drive;
}
let drive = new Car();
drive(); // 4 wheel run
複製代碼
你們確定都寫過相似的代碼,這段代碼使用了閉包;那麼到底閉包是什麼?如何分析出閉包爲何產生和閉包到底在哪裏?緩存
閉包是由函數以及建立該函數的詞法環境組合而成,閉包具有的幾點要素bash
爲了讓你們清晰的看到,咱們藉助chrome的調試工具看下閉包產生的過程。 閉包
當js執行到 let drive = new Car();代碼,在執行car()時,此時的Call Stack只有全局上下文。函數
接下來執行car(); 咱們能夠看到,此時的drive進入了Call Stack,而且Closure(Car) 造成了。工具
經過調試,咱們看到當函數car執行時,閉包才產生,而封閉的空間Car時閉包。性能
閉包是js中的一個重要的存在,它能讓不少不可能實現成爲可能,可是閉包雖好,可是也不能亂用,有的時候也會拔苗助長。ui
JS分配給瀏覽器的可用內存數量一般比分配給桌面應用程序的少,主要是防止js的網頁所有講系統內存耗盡。咱們要想讓頁面具有更好的性能就必須保證頁面佔用最少的內存,也就是說,咱們應該保證執行的代碼只保存有用的數據,一旦數據再也不有用,咱們就該進行垃圾回收,釋放內存。閉包是阻止垃圾回收的,所以變量永遠存在內存中。當變量再也不被使用時,會形成內存泄漏,會影響頁面的性能。spa
所以當變量對象再也不使用的時候,咱們應該將其釋放掉。
function Car () {
let wheel = 4;
function drive () {
console.log(wheel + ' wheel run');
}
return drive;
}
let drive = new Car();
drive(); // 4 wheel run
drive = null; // 在drive再也不使用,將其指向對象釋放
複製代碼
var module = (function (window, undefined) {
let name = '王小端Coder';
function getName () {
return name;
}
return {
name,
getName
}
})(window);
console.log(module.name); // 王小端Coder
console.log(module.getName()); // 王小端Coder
複製代碼
一個模塊具備私有屬性、私有方法和公有屬性、公有方法,而閉包能很好的將模塊的公有屬性、方法暴露出來。return關鍵字將對象引用賦值給module,從而使用的閉包。
for (var i = 0; i < 5; i++) {
setTimeout(() => {
console.log(i);
}, 1000 * i);
}
複製代碼
在上面這個例子中咱們實際上想依次輸出 0,1,2,3,4;而不是如今的輸出5個5。下面咱們進行改造。
for (var i = 0;i < 5; i++) {
(j => {
setTimeout(() => {
console.log(j);
}, 1000 * j);
})(i)
}
複製代碼
在setTimeout中應用了閉包,使其內部可以記住每次循環所在的詞法做用域和做用域鏈。因爲setTimeout中的回調函數會在當前任務隊列的尾部進行執行,所以上面第一個例子中每次循環中的setTimeout回調函數記住的i的值是for循環做用域中的值,此時都是5,而第二個例子記住的i的數爲setTimeout的父級做用域自執行函數中的j的值,依次爲0,1,2,3,4。
var fn = function () {
var sum = 0;
for (var i = 0; i < arguments.length; i++) {
sum += arguments[i];
}
return sum;
}
複製代碼
這個函數是返回傳遞參數之和,若是每次傳遞參數一致。結果返回都是一致的,就會形成浪費。若是改造這個函數,提升函數的性能。
var fn = (function () {
var cache = {};
return function () {
var str = JSON.stringify(arguments);
if (cache[str]) {
return cache[str];
} else {
var sum = 0;
for (var i = 0; i < arguments.length; i++) {
sum += arguments[i];
}
return cache[str] = sum;
}
}
})();
複製代碼
上面的示例將計算後的結果緩存到局部變量cache當中,在調用這個函數時,先在緩存中查找,若是找不到,則進行計算,而後將結果放到緩存中並返回,若是找到了,直接返回查找到的值。
若有對閉包的理解不正確的地方歡迎你們指正。謝謝!