1,js的鍊式作用域
[html]
view plain
copy
- <!DOCTYPE html>
- <html>
- <head>
- <script type="text/javascript">
- //js鍊式作用域:父對象的所有變量,對子對象都是可見的,反之則不成立。
- function f1(){
- n=1;
- function f2(){
- var n2=11;
- alert("f2:n="+n);
- }
- f2();//1
- alert("n2:"+n2);//提示n2 is not defined。
- }
- f1();
- </script>
- </head>
- <body></body>
- </html>
2,閉包
上方代碼中的f2函數就是閉包。
可以了解為:閉包就是可以通路其他函數内部變量的函數,例如f2通路f1,也了解為局部變量函數,因為f2就是f1的子函數。
3,閉包的用途
閉包的用處很多,最大通常有兩個:一個是讀取函數内部變量(f2讀取f1),另一個是讓這些變量的值始終保持在記憶體中。
第一種用途可以從上方代碼中看到,看第二種用途:
[html]
view plain
copy
- <!DOCTYPE html>
- <html>
- <head>
- <script type="text/javascript">
- function f1(){
- var n=1;
- nAdd=function(){
- n+=1;
- }
- //f2把n儲存在記憶體中
- function f2(){
- alert("f2:n="+n);
- }
- return f2;
- }
- var result=f1();
- result(); //n=1,記憶體中有n=1
- nAdd();//記憶體中n+1
- result(); //n=2
- </script>
- </head>
- <body></body>
- </html>
這個代碼中可以看到,f2運作了兩次,從第二次運作結果可以看到,n并沒有在第一次運作之後被清楚。
原因在于:f1是f2的父函數,而f2被賦給了一個全局變量(result),這導緻f2始終在記憶體中,而f2的存在依賴于f1,是以f1也始終在記憶體中,不會在調用結束後,被垃圾回收機制(garbage collection)回收。注意代碼中的匿名函數nAdd,這個也是閉包,且相當于一個set函數,函數外部調用可以給局部變量指派。
4,使用閉包注意
1)由于閉包會使得函數中的變量都被儲存在記憶體中,記憶體消耗很大,是以不能濫用閉包,否則會造成網頁的性能問題,在IE中可能導緻記憶體洩露。解決方法是,在退出函數之前,将不使用的局部變量全部删除。
2)閉包會在父函數外部,改變父函數内部變量的值。是以,如果你把父函數當作對象(object)使用,把閉包當作它的公用方法(Public Method),把内部變量當作它的私有屬性(private value),這時一定要小心,不要随便改變父函數内部變量的值。
5,終極代碼
(1)
[html]
view plain
copy
- <!DOCTYPE html>
- <html>
- <head>
- <script type="text/javascript">
- var name = "The Window";
- var object = {
- name : "My Object",
- getNameFunc : function(){
- return function(){
- return this.name;
- };
- }
- };
- alert(object.getNameFunc()()); //The Window
- </script>
- </head>
- <body></body>
- </html>
解決這個問題,首先清楚this指的是什麼。可以在getNameFunc中alert一下,發現是window,就是全局環境,因為是全局變量,是以輸出“The Window”,問題是為什麼this指的是全局環境,參考:js中的this .
(2)
[javascript]
view plain
copy
- <!DOCTYPE html>
- <html>
- <head>
- <script type="text/javascript">
- function outerFun(){
- var a=0;
- function innerFun(){
- a++;
- alert(a);
- }
- return innerFun; //注意這裡
- }
- var obj=outerFun();
- obj(); //結果為1
- obj(); //結果為2
- var obj2=outerFun();
- obj2(); //結果為1
- obj2(); //結果為2
- </script>
- </head>
- <body></body>
- </html>