阮一峰大佬的文章
-
1. 什么是閉包云茸?
我的理解是,閉包就是能夠讀取其他函數內部變量的函數妹萨。
由于在Javascript語言中年枕,只有函數內部的子函數才能讀取局部變量,因此可
以把閉包簡單理解成"定義在一個函數內部的函數"乎完。 -
2. 閉包的用途
-
可以讀取函數內部的變量
簡單來說JS語言具備的特點之一熏兄,即子函數可以獲取全局變量,而函數外部無法獲取到函數內的局部變量树姨,在某些特定的情況下我們需要獲取函數內部的局部變量即可通過一些變通的方法達成目的摩桶。
function f1(){ var n=999; function f2(){ alert(n); // 999 } }
Javascript語言特有的"鏈式作用域"結構(chain scope),子對象會一級一級地向上尋找所有父對象的變量帽揪。所以硝清,父對象的所有變量,對子對象都是可見的转晰,反之則不成立芦拿。
因此利用JS語言的此種特性,
在目標函數內部定義一個函數就可以目標函數的局部變量暴露出來 -
讓這些變量的值始終保持在內存中
還是上大佬的栗子
function f1(){ var n=999; nAdd=function(){n+=1} function f2(){ alert(n); } return f2; } var result=f1(); result(); // 999 nAdd(); result(); // 1000
在這段代碼中挽霉,result實際上就是閉包f2函數防嗡。它一共運行了兩次,第一次的值是999,第二次的值是1000。這證明了干发,函數f1中的局部變量n一直保存在內存中,并沒有在f1調用后被自動清除他嫡。
為什么會這樣呢?原因就在于f1是f2的父函數庐完,而f2被賦給了一個全局變量钢属,這導致f2始終在內存中,而f2的存在依賴于f1门躯,因此f1也始終在內存中淆党,不會在調用結束后,被垃圾回收機制(garbage collection)回收讶凉。
這段代碼中另一個值得注意的地方染乌,就是"nAdd=function(){n+=1}"這一行,首先在nAdd前面沒有使用var關鍵字懂讯,因此nAdd是一個全局變量荷憋,而不是局部變量。其次褐望,nAdd的值是一個匿名函數(anonymous function)勒庄,而這個匿名函數本身也是一個閉包串前,所以nAdd相當于是一個setter,可以在函數外部對函數內部的局部變量進行操作实蔽。
-
-
3. 使用閉包需要注意的點
1)由于閉包會使得函數中的變量都被保存在內存中荡碾,內存消耗很大,所以不能濫用閉包局装,否則會造成網頁的性能問題玩荠,在IE中可能導致內存泄露。解決方法是贼邓,在退出函數之前,將不使用的局部變量全部刪除闷尿。
2)閉包會在父函數外部塑径,改變父函數內部變量的值。所以填具,如果你把父函數當作對象(object)使用统舀,把閉包當作它的公用方法(Public Method),把內部變量當作它的私有屬性(private value)劳景,這時一定要小心誉简,不要隨便改變父函數內部變量的值。
-
4. 阮一峰大佬的思考題 1
題目
image.png
最終輸出結果是The Window
下面強行分析一波
alert輸出 object對象的 getNameFunc()函數盟广,此時getNameFunc()函數的函數定義為
function(){
return this.name;
};
同時getNameFunc()函數的調用上下文應當為全局 windows闷串,因此當函數再找不到this.name定義的時候會向上,也就是當前調用上下文也就是windows尋找筋量,于是發(fā)現 name是有定義的烹吵,所以第一個思考題輸出結果為The Windows
-
5. 阮一峰大佬的思考題 2
題目
image.png
這一道題在函數getNameFunc()內部有一句
var that = this;
我們都知道this的指向取決于調用上下文 而不是他所在的代碼塊桨武,因此此時的this實際指向的應當是object對象肋拔,所以當函數在尋找that.name定義的時候,會找到他的調用上下文object
因此這道題會輸出 My Object