天天看點

javascript成神之路(5):真正了解什麼是閉包一、閉包是什麼二、閉包産生三、特殊的閉包四、常見的閉包(項目總最經常碰到的)--循環閉包五、閉包的作用六、閉包的弊端或者缺點七、閉包造成記憶體洩露的原因

摘要:了解了閉包,你可以從之前的“道士”變成有修為的“半仙人”
javascript成神之路(5):真正了解什麼是閉包一、閉包是什麼二、閉包産生三、特殊的閉包四、常見的閉包(項目總最經常碰到的)--循環閉包五、閉包的作用六、閉包的弊端或者缺點七、閉包造成記憶體洩露的原因

一、閉包是什麼

在函數外部無法通路函數内部的變量,而函數内可以通路函數外的變量,在函數的内部,嵌套一個子函數,這個子函數可以通路父函數作用域内的變量,然後父函數把這個子函數return出去,讓在函數外部可以通過子函數通路自己的局部變量,是不是有點懵呢?我們看個例子:

var x = 20; function F() { alert(x); // 自由變量"x" == 20 } // 為F閉包 fooClosure = { call: F // 引用到function lexicalEnvironment: {x: 20} // 搜尋上下文的上下文 };

此時,“F”函數已經有了一個内部屬性——建立該函數上下文的作用域鍊。

二、閉包産生

說白了,閉包的産生就是函數内嵌套函數,例如:

var F=function(){ var a=1; return function(){ a++; alert(a); } } var f=F(); f();

這個時候,f()能夠通路F的内部作用域,然後把裡面的匿名函數function()本身當作一個值類型進行傳遞,其實這個閉包的産生過程可以了解為在裡面的匿名函數定義時正處于懷孕的階段,到外面f()調用時,小孩就出生了,這個小孩(難道是哪吒?)就是閉包。

三、特殊的閉包

有時候對函數類型的值進行參數傳遞有很多種方法,沒關系,當他們在别處被調用時仍然可以觀察到閉包,例如:

function F(){ var a=2; function B(){ console.log(a);//2 } BB(B); } function BB(fn){ fn();//這個就是閉包 } //這個是把内部的函數B傳遞給BB,當調用這個内部函數時,它涵蓋的F()内部作用域就出來了,因為它能夠通路a. //閉包第二發 function W(msg){ setTimeout(function T(){ console.log(msg); },1000); } W("Hello,closure!");

四、常見的閉包(項目總最經常碰到的)--循環閉包

for(var i=1;i<=5;i++){ (function(){ var j=i; setTimeout(function trimer(){ console.log(j); },j*1000); })(); }

在for循環裡面,我們在每個疊代過程中都建立了一個閉包作用域,且作用域内定義了變量,進行了指派。閉包改變了變量的生命周期,變量将得到永生。

五、閉包的作用

1、函數外部讀取函數内的局部變量 2、儲存變量于記憶體中,避免全局變量的污染

有時候需要一個子產品中定義這樣的變量,執行某些操作後,始終儲存上一次的值,希望這個變量一直儲存在記憶體中,但又不會污染全局變量,這個時候,我們就可以使用閉包,這就為什麼在不同的函數子產品内定義變量名相同的辨別符,但互相之間卻又不相幹擾的原因,本質上就是閉包詞法作用域在起作用

3、對外提供公有的屬性和方法(具體代碼我就不寫了,我想大家應該有一個比較系統的了解了)

六、閉包的弊端或者缺點

1、由于閉包會使得函數中的變量會被儲存在記憶體中,因常駐在記憶體中,如果變量對象不使用會比較占用記憶體,在IE8以下浏覽器會造成記憶體洩露,解決辦法,就是在退出函數之前,将不使用的局部變量全部删除清空就可以了
2、如果你把父函數當做對象使用,把閉包當做它的公有方法,把内部變量當做它的私有屬性,這時候,要注意不要随便的改變父函數的内部變量的值

七、閉包造成記憶體洩露的原因

IE8低版本浏覽器下js引擎與DOM對象垃圾回收機制不同,js對象循環計數導緻記憶體洩露可用閉包詞法作用域解決,js對象與DOM對象互相引用迹某些DOM操作導緻記憶體洩露

原文釋出時間:2018年01月10日

作者:

技術金三胖

本文來源:

開源中國

  如需轉載請聯系原作者

繼續閱讀