精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

重學JavaScript(函數)閉包

開發 后端
JavaScript函數內部可以讀取函數外部的變,但反過來,函數的外部通常則無法讀取函數內部的變量。在實際應用中,有時需要真正在函數外部訪問函數內部的局部變量,此時最常用的方法就是使用閉包。

 前言
我們知道,作用域鏈查找標識符的順序是從當前作用域開始一級一級往上查找。因此,通過作用域鏈,JavaScript函數內部可以讀取函數外部的變,但反過來,函數的外部通常則無法讀取函數內部的變量。在實際應用中,有時需要真正在函數外部訪問函數內部的局部變量,此時最常用的方法就是使用閉包。

那么什么是閉包?所謂閉包,就是同時含有對函數對象以及作用域對象引用的對象。閉包主要是用來獲取作用域鏈或原型鏈上的變量或值。創建閉包最常見的方式是在一個函數中聲明內部函數(也稱嵌套函數),并返回內部函數。此時在函數外部就可以通過調用函數得到內部函數。雖然按照閉包的概念,所有訪問了外部變量的JavaScript函數都是閉包。但我們平常絕大部分時候所謂的閉包其實指的就是內部函數閉包。
閉包可以將一些數據封裝私有屬性以確保這些變量的安全訪問,這個功能給應用帶來了極大的好處。需要注意的是,閉包如果使用不當,也會帶來一些意想不到的問題。下面就通過幾個示例來演示一下閉包的創建、使用和可能存在的問題及其解決方法。
示例1: 創建閉包。

  1. <!DOCTYPE html> 
  2. <html> 
  3. <head> 
  4.  <title>閉包</title> 
  5. </head> 
  6. <body> 
  7. <script type="text/javascript"
  8.  function outer(argument) { 
  9.   var b=0; 
  10.   return function inner (){ 
  11.    b++; 
  12.    console.log("內部的b:"+b); 
  13.   } 
  14.  } 
  15.  var func =  outer();//1 通過外部變量引用函數返回的內部函數 
  16.  console.log(func);//2 輸出內部函數定義代碼 
  17.  func();//3 通過閉包訪問局部變量b,此時b=1; 
  18.  console.log("外部函數中b:"+b); //4 出錯,報引用錯誤。 
  19. </script> 
  20. </body> 
  21. </html> 

上述代碼在外部函數outer中聲明內部函數inner,并返回內部函數,同時在outer函數外面,變量func引用了outer函數返回的內部函數,所以內部函數inner是一個閉包。該閉包訪問了外部函數的局部變量b。1處代碼通過調用外部函數返回內部函數并賦給外部變量func,使func變量引用內部函數,所以2處代碼將輸出inner函數的整個定義代碼。3處代碼通過對外部變量func添加一對小括號后調用內部函數inner,從而達到在函數外部訪問局部變量b的目的。執行4處的代碼時將報ReferenceError錯誤,因為b是局部變量,不能在函數外部直接訪問局部變量。
我們知道函數執行完畢時,運行期上下文會被銷毀,與之關聯的活動對象也會隨之銷毀,因此離開函數后,屬于活動對象的局部變量將不能被訪問。但是為什么上述示例中的outer函數執行完后,它的局部變量還能被內部函數訪問呢?這個問題我們可以用作用域鏈來解釋。
當執行1處代碼調用outer函數時,JavaScript引擎會創建outer函數執行上下文的作用域鏈,這個作用域鏈包含了outer函數執行時的活動對象,同時JavaScript引擎也會創建一個閉包,而閉包因為需要訪問outer函數的局部變量,因而其作用鏈也會引用outer的活動對象。這樣,當outer函數執行完后,它的作用域對象因為有閉包的引用而依然存在,固而可以提供給閉包訪問。
上述示例中的內部函數雖然有名稱,但在調用是并沒有用到這個名稱,所以內部函數的名稱可以缺省,即可以將內部函數修改為匿名函數,從而簡化代碼。
示例2: 經典閉包問題

  1. <!DOCTYPE html> 
  2. <html> 
  3. <head> 
  4. <title>經典閉包問題</title> 
  5. <script type="text/javascript"
  6.  window.onload=function () { 
  7.   var abtn = document.getElementsByTagName("button"); 
  8.   for (var i = 0; i<abtn.length; i++) { 
  9.    abtn[i].onclick=function(){ 
  10.     alert("按鈕"+(i+1)); 
  11.    } 
  12.   } 
  13.  } 
  14. </script> 
  15. </head> 
  16. <body> 
  17. <button>按鈕1</button> 
  18. <button>按鈕2</button> 
  19. <button>按鈕3</button> 
  20. </body> 
  21. </html> 

該示例期望實現的功能是,單擊每個按鈕時,在彈出的警告對話框中顯示相應的標簽內容,即單擊3個按鈕時將分別顯示“按鈕1”、“按鈕2”、“按鈕3”。
上述示例頁面加載完后觸發窗口加載事件,從而執行外層匿名函數,外層匿名函數執行完循環語句后使活動對象中的局部變量i的值修改為3。外層匿名函數執行完后撤銷,但由于其活動對象中的abtn和i變量被內層匿名函數引用,因而外層匿名函數的活動對象仍然存在堆中供內層匿名函數訪問。每執行一次循環都將創建一個閉包,這些閉包都引用了外層匿名函數的活動對象,因而訪問變量i時都得到3,這樣最后的結果是單擊每個按鈕,在警告對話框中顯示的文字都是“按鈕4” (i+1=3+1),與期望的功能不一致。造成這個問題的原因是,每個閉包都引用一個變量,如果我們使不同的閉包引用不同的變量,就可以實現輸出的結果不一樣。這個需求可使用多種方法實現,在此介紹使用立即調用函數表達式(IIFE)和ES6中的let創建塊即變量的方法。
IIFE指的是:在定義函數的時候直接執行,即此時函數定義變成了一個函數調用的語句。要讓一個函數定義語句變成函數調用語句,就需要將定義語句變為一個函數表達式,然后在該表達式后面再加一對圓括號()即可。將函數定義語句變為一個函數表達式的最常用方法就是將整個定義語句放在一對圓括號中。
1、IIFE中的函數為一個匿名函數

  1. (function(name){ 
  2.  console.log("hello,"+name); 
  3. })("maomin"); 

JS引擎執行上述代碼時,會調用匿名,同時將后面圓括號中的參數maomin傳給name虛參,結果得到:"hello,maomin"。
2、IIFE中的函數為一個有名函數

  1. (function func (name) { 
  2.  console.log("I am"+name); 
  3. })("maomin"

上述代碼跟匿名函數完全一樣。

示例3: 使用立即調用函數表達式解決經典閉包問題

  1. <!DOCTYPE html> 
  2. <html> 
  3. <head> 
  4.  <title>使用立即調用表達式解決經典閉包問題</title> 
  5.  <script type="text/javascript"
  6.  window.onload=function () { 
  7.   var abtn = document.getElementsByTagName("button"); 
  8.   for (var i = 0; i<abtn.length; i++) { 
  9.    (function(num){ 
  10.     abtn[num].onclick=function(){ 
  11.         alert("按鈕"+(num+1)); 
  12.        } 
  13.    })(i) 
  14.   } 
  15.  } 
  16. </script> 
  17. </head> 
  18. <body> 
  19. <button>按鈕1</button> 
  20. <button>按鈕2</button> 
  21. <button>按鈕3</button> 
  22. </body> 
  23. </html> 

上述代碼中第二個匿名函數為IIFE,每次調用該匿名函數時將生成一個對應該函數的活動對象。該對象中包含可一個函數參數,值為當次循環的循環變量值。上述示例中,IIFE共執行了3次,因而共生成了3個活動對象,活動對象中包含的參數值分別為0、1和2,依次對應IIFE的3次執行。
每次執行IIFE時,將會產生一個閉包,該閉包會引用對應按鈕索引順序執行IIFE的活動對象,而閉包引用的活動對象中的參數值剛好等于按鈕的索引值,因而單擊3個按鈕將在彈出的警告框中分別顯示"按鈕1"、“按鈕2”、“按鈕3”。
示例4:使用ES6中的let關鍵字創建塊級變量解決經典閉包問題

  1. <!DOCTYPE html> 
  2. <html> 
  3. <head> 
  4.  <title>使用ES6中的let關鍵字解決經典閉包問題</title> 
  5.  <script type="text/javascript"
  6.  window.onload=function () { 
  7.   var abtn = document.getElementsByTagName("button"); 
  8.   for (let i = 0; i<abtn.length; i++) { 
  9.    abtn[i].onclick=function(){ 
  10.     alert("按鈕"+(i+1)); 
  11.    } 
  12.   } 
  13.  } 
  14. </script> 
  15. </head> 
  16. <body> 
  17. <button>按鈕1</button> 
  18. <button>按鈕2</button> 
  19. <button>按鈕3</button> 
  20. </body> 
  21. </html> 

上述代碼中循環變量使用let聲明,因而每次循環時,都會產生一個新的塊級變量,所以在頁面加載完,執行外層匿名函數時產生的活動對象中包含了3個對應循環變量的塊級變量,變量值分為0、1和2。每執行一次循環,將會產生一個閉包,該閉包中的變量i會引用外層匿名函數的活動對象對應按鈕索引的塊級變量,因而單擊3個按鈕時將在彈出的警告對話框中分別顯示“按鈕1”、“按鈕2”、“按鈕3”。

責任編輯:姜華 來源: 前端歷劫之路
相關推薦

2021-02-21 16:21:19

JavaScript閉包前端

2011-05-25 14:48:33

Javascript閉包

2021-01-22 07:48:07

JavaScript 高階函數閉包

2016-09-14 09:20:05

JavaScript閉包Web

2009-07-24 17:30:37

Javascript閉

2017-09-14 13:55:57

JavaScript

2021-05-21 09:01:29

JavaScript 前端函數閉包

2016-09-18 20:53:16

JavaScript閉包前端

2017-05-22 16:08:30

前端開發javascript閉包

2009-03-17 15:36:29

JavaScript循環事件

2021-01-13 11:25:12

JavaScript閉包函數

2010-06-23 10:24:42

Javascript閉

2012-11-29 10:09:23

Javascript閉包

2011-05-12 18:26:08

Javascript作用域

2011-05-30 14:41:09

Javascript閉

2011-03-02 12:33:00

JavaScript

2024-01-22 09:51:32

Swift閉包表達式尾隨閉包

2021-12-06 07:15:48

Javascript作用域閉包

2023-07-11 08:46:38

閉包函數Rust

2023-02-07 07:47:52

Python裝飾器函數
點贊
收藏

51CTO技術棧公眾號

中文字幕日韩精品在线观看| 成人av免费观看| 亚洲天堂av高清| 99热一区二区| 午夜精品久久久久久久蜜桃| 大色综合视频网站在线播放| 在线电影院国产精品| 中文字幕第一页亚洲| 人人妻人人澡人人爽精品日本| 亚洲尤物在线| 日韩亚洲第一页| 亚洲熟女一区二区| 国内精品伊人| 亚洲福利电影网| 亚洲狠狠婷婷综合久久久| 国产人妻精品一区二区三| 国产精品日韩欧美一区| 日韩在线观看网址| 亚洲国产精品无码久久久久高潮| 日本免费成人| 欧美日韩日日摸| 高清亚洲成在人网站天堂| 亚洲精品成人无码熟妇在线| 亚洲三级黄色在线观看| 亚洲涩涩在线观看| 九色porny视频在线观看| 亚洲精品中文字幕乱码三区不卡| 日本成人xxx| 欧美××××黑人××性爽| 尤物av一区二区| 日本在线免费观看一区| 国产91麻豆视频| 狠狠色狠狠色综合日日91app| 欧美一区二区三区艳史| 欧美日韩中文字幕在线观看 | 国产精品成人aaaaa网站| 欧美又粗又大又长| 欧美国产小视频| 亚洲欧美另类中文字幕| www国产视频| 亚洲啊v在线免费视频| 欧美日韩电影在线| 美女一区二区三区视频| av电影一区| 岛国av在线不卡| 中文字幕无码精品亚洲资源网久久| 成年人网站在线| 国产亚洲欧美在线| 欧美一区1区三区3区公司 | 亚洲欧洲国产日本综合| 亚洲精品日韩精品| av无码一区二区三区| 青春草在线观看| 成人短片线上看| 裸体一区二区| 九九精品视频在线| 婷婷久久综合网| 999国产精品| 久久精品视频一| 亚洲最大的av网站| 波多野结衣电影在线播放| 国产乱码精品| 51色欧美片视频在线观看| 黄色激情视频在线观看| 夜夜夜久久久| 日本精品va在线观看| 久久国产视频精品| 可以免费看不卡的av网站| 日韩美女视频免费看| 波多野结衣黄色网址| 久久资源在线| 国产美女扒开尿口久久久| 国产乱码久久久| 国产精品18久久久久久久久 | 国产精品第5页| 视频在线在亚洲| 成人精品一区二区三区电影免费| av中文字幕免费| 成人精品视频一区二区三区尤物| 麻豆av一区| h视频网站在线观看| 一区二区中文字幕在线| 亚洲色成人www永久在线观看| 黄频免费在线观看| 欧美天天综合网| 日本一本在线视频| 欧美亚视频在线中文字幕免费| 亚洲第一区第二区| 欧美黄色激情视频| 亚洲精品成人| 91高潮精品免费porn| 中日韩av在线| 成人一区二区三区| 日本精品一区二区三区不卡无字幕| 日日摸天天爽天天爽视频| 欧洲中文在线| 欧美日韩综合视频| 潘金莲激情呻吟欲求不满视频| 麻豆一区在线| 亚洲视频视频在线| a级片在线观看免费| 久久久久久久波多野高潮日日| 91久久国产精品91久久性色| 天天干天天色天天| 中文字幕一区二区三区乱码在线| 大陆av在线播放| 日韩av懂色| 日韩激情av在线播放| 国产色无码精品视频国产| 国产农村妇女精品一区二区| 成人国产精品久久久久久亚洲| 午夜一区在线观看| 亚洲欧美日韩久久| 国产av人人夜夜澡人人爽| 在线观看视频一区二区三区 | av网站网址在线观看| 日韩欧美中文字幕在线观看 | 久久夜色精品国产欧美乱极品| 亚洲国产精品二区| 久久xxxx| 99久久精品无码一区二区毛片| 欧洲视频在线免费观看| 中文字幕色av一区二区三区| 免费黄色日本网站| 1769国产精品视频| 久久久精品日本| www.av88| 国产亚洲一区二区三区| a级黄色一级片| 亚洲网一区二区三区| 红桃成人av在线播放| 欧洲日韩一区二区三区| 老司机免费视频| 欧美视频二区| 91精品美女在线| av网站无病毒在线| 色域天天综合网| 精品无码在线视频| 亚洲国产清纯| 国产精品三区在线| 国产盗摄精品一区二区酒店| 91麻豆精品91久久久久久清纯| 久久中文字幕精品| 视频一区中文字幕| 欧美日韩在线精品| www.成人爱| 亚洲欧美日韩综合| 国产成人精品网| 91免费观看在线| 久久婷婷国产精品| 亚洲免费福利一区| 欧美亚州一区二区三区| 亚洲欧美综合在线观看| 欧美日韩免费观看中文| 国产美女喷水视频| 丝袜美腿一区二区三区| 日本高清一区| 久久影视精品| 久久亚洲欧美日韩精品专区| 99久久久国产精品无码免费| 亚洲精品视频一区二区| 在线播放第一页| 国产日韩亚洲欧美精品| 欧美一区二区三区精美影视| 日韩经典一区| 不卡av日日日| 欧美 日韩 国产 精品| 狠狠色狠色综合曰曰| 亚洲精品国产91| 麻豆精品一区二区综合av| 亚洲成人动漫在线| 欧美人妖视频| 国产精品va在线| 超碰在线观看免费| 亚洲国产精彩中文乱码av| 黄色片免费观看视频| 欧美经典一区二区| 超碰在线资源站| 亚洲狠狠婷婷| 日本黑人久久| 日韩精品中文字幕吗一区二区| 午夜精品久久久久久久白皮肤| 可以免费看污视频的网站在线| 欧美三级在线看| 欧美黑吊大战白妞| 久久中文娱乐网| 亚洲国产午夜精品| 亚洲欧美日韩视频二区| 亚洲欧洲精品一区二区| 亚洲日本va中文字幕| 欧美在线视频观看| 国产精品一区二区三区视频网站| 亚洲国产欧美久久| 91中文字幕在线视频| 香蕉av福利精品导航| 美国一级黄色录像| www.亚洲免费av| 亚洲精品20p| 麻豆成人精品| 免费看欧美黑人毛片| 俺要去色综合狠狠| 激情一区二区三区| 高清久久一区| 色婷婷亚洲婷婷| 九九九久久久| 亚洲国产综合在线观看| 欧美亚洲视频一区二区| av在线免费观看网址| 亚洲视频电影图片偷拍一区| 亚洲高清精品视频| 欧美欧美午夜aⅴ在线观看| 色网站在线播放| 亚洲精品高清视频在线观看| 久久婷婷五月综合| 成人激情文学综合网| 性chinese极品按摩| 一区二区三区高清视频在线观看| 中文字幕一区二区三区四区五区| 精品在线手机视频| 国产伦精品一区二区三区照片91| 国产精品一区二区美女视频免费看| 日韩av电影手机在线观看| 国产蜜臀一区二区打屁股调教| 综合激情国产一区| 狠狠v欧美ⅴ日韩v亚洲v大胸| 亚洲精品一区二区三区四区高清 | 亚洲图区一区| 日韩中文字幕在线视频| 国产福利免费在线观看| 亚洲美女av黄| 天堂在线中文资源| 欧美黄色网络| 国产精品你懂得| 免费亚洲电影| 欧美在线视频一区| 久久综合激情网| 天美av一区二区三区久久| 亚洲自拍高清视频网站| 成人亚洲精品| 成人黄色激情网| 久久精品xxxxx| 国产精品自拍偷拍| 男人亚洲天堂| 成人在线播放av| 国产一区二区| 北条麻妃高清一区| 成人午夜三级| 国产精品国产三级欧美二区 | 超碰中文在线| 久久久久久成人精品| 久久av色综合| 97精品一区二区视频在线观看| 操喷在线视频| 26uuu亚洲伊人春色| 欧美1级2级| 国产精品久久久久久久美男| 成人国产一区| 91久久久久久久久久久| 午夜视频一区二区在线观看| 国产精品视频一区二区三区经| 欧美激情影院| 日韩av电影免费播放| 成人在线一区| 一区二区三区四区在线视频| 亚洲免费二区| cao在线观看| 久久精品电影| 手机看片一级片| 国产剧情在线观看一区二区| 午夜不卡久久精品无码免费| 91社区在线播放| 中文字幕在线观看二区| 亚洲激情欧美激情| 久久国产精品免费看| 在线亚洲免费视频| 国产女无套免费视频| 欧美精品一区在线观看| 飘雪影视在线观看免费观看| 三级精品视频久久久久| 久久香蕉一区| 国产精品嫩草影院一区二区| 综合视频一区| 日本一区二区不卡高清更新| 久久精品一区二区不卡| 亚洲 自拍 另类小说综合图区| 日日夜夜精品视频免费| 18深夜在线观看免费视频| a毛片不卡免费看片| 日本道精品一区二区三区| 一级日韩一级欧美| 亚洲国产精品va在线看黑人动漫 | 欧美精品第一页在线播放| 精品国产第一福利网站| 成人国产精品色哟哟| 欧美理伦片在线播放| 亚洲午夜精品久久| 日韩午夜高潮| 手机av在线网站| 久久久久99精品一区| 日本精品人妻无码77777| 午夜一区二区三区视频| 91影院在线播放| 亚洲欧美另类在线观看| 亚洲毛片播放| 一区二区精品在线| 91久久视频| 男生操女生视频在线观看| hitomi一区二区三区精品| аⅴ天堂中文在线网| 亚洲午夜视频在线观看| 怡春院在线视频| 精品亚洲一区二区| 欧美性受ⅹ╳╳╳黑人a性爽| 国产精品99久久久久久久久| 国产精品极品在线观看| 亚洲免费av网| 免费看黄色91| 西西444www无码大胆| 天天免费综合色| 精品国产亚洲av麻豆| 日韩中文字幕网址| 三级成人在线| 美媛馆国产精品一区二区| 国产精品大片| 在线成人免费av| 亚洲欧洲日产国产综合网| 在线免费观看一区二区| 亚洲色图激情小说| 中日韩脚交footjobhd| 国产三级精品在线不卡| 国产少妇在线观看| 综合在线观看色| 一级黄色片在线观看| 中日韩美女免费视频网站在线观看| 中文字幕在线官网| 久久综合九色欧美狠狠| 中文久久精品| 午夜一区二区三区免费| 精品国产乱码久久久久久虫虫漫画| 免费观看黄色av| 午夜精品三级视频福利| 九色丨蝌蚪丨成人| 久久久久久www| 91网站视频在线观看| 成年人免费高清视频| 日韩精品在线观看网站| 中文字幕在线视频久| 欧美日韩精品免费观看视一区二区| 亚洲永久视频| 免费成人深夜天涯网站| 欧美日韩一区二区在线观看视频| 亚洲欧美视频一区二区| 成人福利视频网| 欧美激情日韩| 老司机免费视频| 色婷婷综合久久久久中文一区二区| 天堂在线中文资源| 国产精品久久久久999| 成人在线一区| 国产男女无遮挡猛进猛出| 亚洲高清一区二区三区| 无码国产精品一区二区色情男同 | 国产在线视视频有精品| www青青草原| 精品99久久久久久| 中文字幕在线高清| 亚洲欧洲一区二区福利| 国产一区二区三区久久久| 久久久久久福利| 日韩av在线精品| 99热播精品免费| 国产在线拍揄自揄拍无码| 国产91精品一区二区麻豆亚洲| 国产成人自拍视频在线| 伊人久久久久久久久久| 精品视频在线一区| 欧美大片在线播放| 欧美国产日韩一二三区| www.天堂av.com| 日韩**中文字幕毛片| 91成人免费| 一级特黄a大片免费| 欧美日韩免费在线视频| 欧美性爽视频| 亚洲成人一区二区三区| 888奇米影视| 色综合天天狠天天透天天伊人| 日韩人体视频| 在线观看岛国av| 五月天欧美精品| 一区二区三区人妻| 美女www一区二区| 久久久久99精品成人片毛片| 亚洲欧洲国产精品| 久久久久九九精品影院| 日韩毛片在线免费看| 一区二区三区中文免费| 黄网在线观看| 国产视频一区二区三区四区| 老司机免费视频一区二区三区|