自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

關(guān)于JavaScript閉包的應(yīng)用

開(kāi)發(fā) 前端
閉包就是指有權(quán)訪問(wèn)另一個(gè)函數(shù)作用域中的變量的函數(shù)。MDN 上面這么說(shuō):閉包是一種特殊的對(duì)象。它由兩部分構(gòu)成:函數(shù),以及創(chuàng)建該函數(shù)的環(huán)境。環(huán)境由閉包創(chuàng)建時(shí)在作用域中的任何局部變量組成。創(chuàng)建閉包最常見(jiàn)方式,就是在一個(gè)函數(shù)內(nèi)部創(chuàng)建另一個(gè)函數(shù)。

[[171507]]

什么是閉包(Closure)

簡(jiǎn)單講,閉包就是指有權(quán)訪問(wèn)另一個(gè)函數(shù)作用域中的變量的函數(shù)。

MDN 上面這么說(shuō):閉包是一種特殊的對(duì)象。它由兩部分構(gòu)成:函數(shù),以及創(chuàng)建該函數(shù)的環(huán)境。環(huán)境由閉包創(chuàng)建時(shí)在作用域中的任何局部變量組成。

但是,網(wǎng)上找了好多資料,它們對(duì)閉包的定義也各有各樣,搞得我也不知道怎么去定義閉包了,所以干脆不去定義了,意會(huì)吧。

道可道,非常道;名可名,非常名。

產(chǎn)生一個(gè)閉包

創(chuàng)建閉包最常見(jiàn)方式,就是在一個(gè)函數(shù)內(nèi)部創(chuàng)建另一個(gè)函數(shù)。下面例子中的 closure 就是一個(gè)閉包:

  1. function func(){ 
  2.   var a = 1,b = 2; 
  3.    
  4.   function closure(){ 
  5.     return a+b; 
  6.   } 
  7.   return closure; 
  8.  

閉包的作用域鏈包含著它自己的作用域,以及包含它的函數(shù)的作用域和全局作用域。

閉包的注意事項(xiàng)

通常,函數(shù)的作用域及其所有變量都會(huì)在函數(shù)執(zhí)行結(jié)束后被銷(xiāo)毀。但是,在創(chuàng)建了一個(gè)閉包以后,這個(gè)函數(shù)的作用域就會(huì)一直保存到閉包不存在為止。

  1. function makeAdder(x) { 
  2.   return function(y) { 
  3.     return x + y; 
  4.   }; 
  5.  
  6. var add5 = makeAdder(5); 
  7. var add10 = makeAdder(10); 
  8.  
  9. console.log(add5(2));  // 7 
  10. console.log(add10(2)); // 12 
  11.  
  12. // 釋放對(duì)閉包的引用 
  13. add5 = null
  14. add10 = null 

add5 和 add10 都是閉包。它們共享相同的函數(shù)定義,但是保存了不同的環(huán)境。在 add5 的環(huán)境中,x 為 5。而在 add10 中,x 則為 10。***通過(guò) null 釋放了 add5 和 add10 對(duì)閉包的引用。

在javascript中,如果一個(gè)對(duì)象不再被引用,那么這個(gè)對(duì)象就會(huì)被垃圾回收機(jī)制回收;

如果兩個(gè)對(duì)象互相引用,而不再被第3者所引用,那么這兩個(gè)互相引用的對(duì)象也會(huì)被回收。

閉包只能取得包含函數(shù)中任何變量的***一個(gè)值,這是因?yàn)殚]包所保存的是整個(gè)變量對(duì)象,而不是某個(gè)特殊的變量。

  1. function test(){ 
  2.   var arr = []; 
  3.   for(var i = 0;i < 10;i++){ 
  4.     arr[i] = function(){ 
  5.       return i; 
  6.     }; 
  7.   } 
  8.   for(var a = 0;a < 10;a++){ 
  9.     console.log(arr[a]()); 
  10.   } 
  11. test(); // 連續(xù)打印 10 個(gè) 10  

對(duì)于上面的情況,如果我們改變代碼如下:

  1. function test(){ 
  2.   var arr = []; 
  3.   for(let i = 0;i < 10;i++){  // 僅在這里作出了改動(dòng) 
  4.     arr[i] = function(){ 
  5.       return i; 
  6.     }; 
  7.   } 
  8.   for(var a = 0;a < 10;a++){ 
  9.     console.log(arr[a]()); 
  10.   } 
  11. test(); // 打印 0 到 9  

對(duì)于上面兩種代碼的解釋,請(qǐng)看我在 segmentfault 上面的提問(wèn):鏈接

閉包中的 this 對(duì)象

  1. var name = "The Window"
  2.  
  3. var obj = { 
  4.   name"My Object"
  5.    
  6.   getName: function(){ 
  7.     return function(){ 
  8.       return this.name
  9.     }; 
  10.   } 
  11. }; 
  12.  
  13. console.log(obj.getName()());  // The Window  

obj.getName()()實(shí)際上是在全局作用域中調(diào)用了匿名函數(shù),this指向了window。這里要理解函數(shù)名與函數(shù)功能(或者稱函數(shù)值)是分割開(kāi)的,不要認(rèn)為函數(shù)在哪里,其內(nèi)部的this就指向哪里。匿名函數(shù)的執(zhí)行環(huán)境具有全局性,因此其 this 對(duì)象通常指向 window。 

  1. var name = "The Window"
  2.  
  3. var obj = { 
  4.   name"My Object"
  5.    
  6.   getName: function(){ 
  7.     var that = this; 
  8.     return function(){ 
  9.       return that.name
  10.     }; 
  11.   } 
  12. }; 
  13.  
  14. console.log(obj.getName()());  // My Object  

閉包的應(yīng)用

應(yīng)用閉包的主要場(chǎng)合是:設(shè)計(jì)私有的方法和變量。

任何在函數(shù)中定義的變量,都可以認(rèn)為是私有變量,因?yàn)椴荒茉诤瘮?shù)外部訪問(wèn)這些變量。私有變量包括函數(shù)的參數(shù)、局部變量和函數(shù)內(nèi)定義的其他函數(shù)。

把有權(quán)訪問(wèn)私有變量的公有方法稱為特權(quán)方法(privileged method)。

  1. function Animal(){ 
  2.    
  3.   // 私有變量 
  4.   var series = "哺乳動(dòng)物"
  5.   function run(){ 
  6.     console.log("Run!!!"); 
  7.   } 
  8.    
  9.   // 特權(quán)方法 
  10.   this.getSeries = function(){ 
  11.     return series; 
  12.   }; 
  13.  

模塊模式(The Module Pattern):為單例創(chuàng)建私有變量和方法。

單例(singleton):指的是只有一個(gè)實(shí)例的對(duì)象。JavaScript 一般以對(duì)象字面量的方式來(lái)創(chuàng)建一個(gè)單例對(duì)象。

  1. var singleton = { 
  2.   name"percy"
  3.   speak:function(){ 
  4.     console.log("speaking!!!"); 
  5.   }, 
  6.   getName: function(){ 
  7.     return this.name
  8.   } 
  9. };  

上面是普通模式創(chuàng)建的單例,下面使用模塊模式創(chuàng)建單例:

  1. var singleton = (function(){ 
  2.    
  3.   // 私有變量 
  4.   var age = 22; 
  5.   var speak = function(){ 
  6.     console.log("speaking!!!"); 
  7.   }; 
  8.    
  9.   // 特權(quán)(或公有)屬性和方法 
  10.   return { 
  11.     name"percy"
  12.     getAge: function(){ 
  13.       return age; 
  14.     } 
  15.   }; 
  16. })();  

匿名函數(shù)***的用途是創(chuàng)建閉包,并且還可以構(gòu)建命名空間,以減少全局變量的使用。從而使用閉包模塊化代碼,減少全局變量的污染。

  1. var objEvent = objEvent || {}; 
  2. (function(){  
  3.     var addEvent = function(){  
  4.       // some code 
  5.     }; 
  6.     function removeEvent(){ 
  7.       // some code 
  8.     } 
  9.  
  10.     objEvent.addEvent = addEvent; 
  11.     objEvent.removeEvent = removeEvent; 
  12. })();  

在這段代碼中函數(shù) addEvent 和 removeEvent 都是局部變量,但我們可以通過(guò)全局變量 objEvent 使用它,這就大大減少了全局變量的使用,增強(qiáng)了網(wǎng)頁(yè)的安全性。

一個(gè)閉包計(jì)數(shù)器 

  1. var countNumber = (function(){ 
  2.   var num = 0; 
  3.   return function(){ 
  4.     return ++num; 
  5.   }; 
  6. })();  

閉包的缺陷

  • 閉包的缺點(diǎn)就是常駐內(nèi)存會(huì)增大內(nèi)存使用量,并且使用不當(dāng)很容易造成內(nèi)存泄露。
  • 如果不是因?yàn)槟承┨厥馊蝿?wù)而需要閉包,在沒(méi)有必要的情況下,在其它函數(shù)中創(chuàng)建函數(shù)是不明智的,因?yàn)殚]包對(duì)腳本性能具有負(fù)面影響,包括處理速度和內(nèi)存消耗。

***再來(lái)一些有關(guān)閉包的面試題

下面代碼中,標(biāo)記 ? 的地方輸出分別是什么?

  1. function fun(n,o){ 
  2.   console.log(o); 
  3.   return { 
  4.     fun: function(m){ 
  5.       return fun(m,n); 
  6.     } 
  7.   }; 
  8.  
  9. var a = fun(0);  // ? 
  10. a.fun(1);        // ?         
  11. a.fun(2);        // ? 
  12. a.fun(3);        // ? 
  13.  
  14. var b = fun(0).fun(1).fun(2).fun(3);  // ? 
  15.  
  16. var c = fun(0).fun(1);  // ? 
  17. c.fun(2);        // ? 
  18. c.fun(3);        // ?  
  1. undefined 
  2. undefined, 0, 1, 2 
  3. undefined, 0 
  4.  

參考資料

責(zé)任編輯:龐桂玉 來(lái)源: segmentfault
相關(guān)推薦

2021-02-21 16:21:19

JavaScript閉包前端

2023-09-06 16:55:33

JavaScript閉包

2020-02-12 16:58:15

JavaScript前端技術(shù)

2009-07-24 17:30:37

Javascript閉

2020-10-14 15:15:28

JavaScript(

2011-05-25 14:48:33

Javascript閉包

2023-11-26 00:34:36

Javascript應(yīng)用方法

2010-06-23 10:24:42

Javascript閉

2016-09-18 20:53:16

JavaScript閉包前端

2012-11-29 10:09:23

Javascript閉包

2017-09-14 13:55:57

JavaScript

2021-05-28 07:12:59

Python閉包函數(shù)

2011-05-12 18:26:08

Javascript作用域

2011-03-02 12:33:00

JavaScript

2009-03-17 15:36:29

JavaScript循環(huán)事件

2017-05-22 16:08:30

前端開(kāi)發(fā)javascript閉包

2021-01-13 11:25:12

JavaScript閉包函數(shù)

2021-12-06 07:15:48

Javascript作用域閉包

2011-08-24 17:09:35

LUA閉包函數(shù)

2010-06-29 08:39:25

Python閉包
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)