亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > JavaScript > 正文

理解和運用JavaScript的閉包機制

2019-11-20 11:50:00
字體:
來源:轉載
供稿:網友

偉大的愛因斯坦同志說過:“如果你無法向一個 6 歲小孩解釋清楚某問題,那說明你自己都沒整明白”。然而,當我向一個 27 歲的朋友解釋什么是閉包時,卻徹底失敗了。

這原本是國外某哥們兒在 Stack Overflow 上對 JavaScript 閉包所提出的問題。不過既然此問題是在 Stack Overflow 提出的,當然也會有很多高手出來解答,其中有些回答確實是經典,如下面這個:

如果在一個外部函數中再定義一個內部函數,即函數嵌套函數,那么內部函數也可以訪問外部函數中的變量:

function foo(x) { var tmp = 3; function bar(y) { alert(x + y + (++tmp)); } bar(10);}foo(2); // alert 16foo(2); // alert 16foo(2); // alert 16

此段代碼可以正確執行,并返回結果:16,因為 bar 能訪問外部函數的變量 tmp, 同時也能訪問外部函數 foo 的參數 x。但以上示例不是閉包!

要實現閉包的話,需要將內部函數作為外部函數的返回值返回,內部函數在返回前,會將所有已訪問過的外部函數中的變量在內存中鎖定,也就是說,這些變量將常駐 bar 的內存中,不會被垃圾回收器回收,如下:

function foo(x) { var tmp = 3; return function (y) { alert(x + y + (++tmp)); }}var bar = foo(2); // bar 現在是個閉包了bar(10); // alert 16bar(10); // alert 17bar(10); // alert 18

上述代碼中,第一次執行 bar 時,仍會返回結果:16,因為 bar 仍然可以訪問 x 及 tmp,盡管它已經不直接存在于 foo 的作用域內。那么既然 tmp 被鎖定在 bar 的閉包里,那么每次執行 bar 的時候,tmp 都會自增一次,所以第二次和第三次執行 bar 時,分別返回 17 和 18。

此示例中,x 僅僅是個純粹的數值,當 foo 被調用時,數值 x 就會作為參數被拷貝至 foo 內。

但是 JavaScript 處理對象的時候,使用的總是引用,如果用一個對象作為參數來調用 foo,那么 foo 中傳入的實際上是原始對象的引用,所以這個原始對象也相當于被閉包了,如下:

function foo(x) { var tmp = 3; return function (y) { alert(x + y + tmp++); x.memb = x.memb ? x.memb + 1 : 1; alert(x.memb); }}var age = new Number(2);var bar = foo(age); // bar 現在是個閉包了bar(10); // alert 15 1bar(10); // alert 16 2bar(10); // alert 17 3

和期望的一樣,每次執行 bar(10) 時,不但 tmp 自增了,x.memb 也自增了,因為函數體內的 x 和函數體外的 age 引用的是同一個對象。

via http://stackoverflow.com/questions/111102/how-do-javascript-closures-work

補充:通過以上示例,應該能比較清楚的理解閉包了。如果覺得自己理解了,可以試著猜猜下面這段代碼的執行結果:

function foo(x) { var tmp = 3; return function (y) { alert(x + y + tmp++); x.memb = x.memb ? x.memb + 1 : 1; alert(x.memb); }}var age = new Number(2);var bar1 = foo(age); // bar1 現在是個閉包了bar1(10); // alert 15 1bar1(10); // alert 16 2bar1(10); // alert 17 3var bar2 = foo(age); // bar2 現在也是個閉包了bar2(10); // alert ? ?bar2(10); // alert ? ?bar2(10); // alert ? ?bar1(10); // alert ? ?bar1(10); // alert ? ?bar1(10); // alert ? ?

實際使用的時候,閉包可以創建出非常優雅的設計,允許對funarg上定義的多種計算方式進行定制。如下就是數組排序的例子,它接受一個排序條件函數作為參數:

[1, 2, 3].sort(function (a, b) { ... // 排序條件});

同樣的例子還有,數組的map方法是根據函數中定義的條件將原數組映射到一個新的數組中:

[1, 2, 3].map(function (element) { return element * 2;}); // [2, 4, 6]

使用函數式參數,可以很方便的實現一個搜索方法,并且可以支持無限制的搜索條件:

someCollection.find(function (element) { return element.someProperty == 'searchCondition';});

還有應用函數,比如常見的forEach方法,將函數應用到每個數組元素:

[1, 2, 3].forEach(function (element) { if (element % 2 != 0) {  alert(element); }}); // 1, 3

順便提下,函數對象的 apply 和 call方法,在函數式編程中也可以用作應用函數。 這里,我們將它們看作是應用函數 ―― 應用到參數中的函數(在apply中是參數列表,在call中是獨立的參數):

(function () { alert([].join.call(arguments, ';')); // 1;2;3}).apply(this, [1, 2, 3]);

閉包還有另外一個非常重要的應用 ―― 延遲調用:

var a = 10;setTimeout(function () { alert(a); // 10, after one second}, 1000);還有回調函數://...var x = 10;// only for examplexmlHttpRequestObject.onreadystatechange = function () { // 當數據就緒的時候,才會調用; // 這里,不論是在哪個上下文中創建 // 此時變量“x”的值已經存在了 alert(x); // 10};//...

還可以創建封裝的作用域來隱藏輔助對象:

var foo = {};// 初始化(function (object) { var x = 10; object.getX = function _getX() {  return x; };})(foo);alert(foo.getX()); // 獲得閉包 "x" 亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

亚洲福利视频久久| 亚洲欧美激情四射在线日| 在线国产精品播放| 成人综合网网址| 国产精品久久999| 久久九九亚洲综合| 国产精品日韩在线| 亚洲最大的免费| 91成人福利在线| 欧洲成人免费视频| 日韩最新av在线| 日本高清视频精品| 日韩精品在线观看网站| 清纯唯美亚洲激情| 91探花福利精品国产自产在线| 一区二区三区视频在线| 日韩欧美在线视频日韩欧美在线视频| 久久99精品久久久久久青青91| 26uuu国产精品视频| 成人字幕网zmw| 欧美激情乱人伦| 国产精品丝袜久久久久久高清| 亚洲成人黄色网| 午夜精品三级视频福利| 久久大大胆人体| 69久久夜色精品国产69| 视频在线观看一区二区| 国产精品久久久久久久久免费看| 精品福利在线视频| 欧美性资源免费| 日韩精品久久久久久福利| 久久亚洲精品视频| 国产亚洲精品久久久久久| 日韩资源在线观看| 国产精品丝袜视频| 欧美成人精品一区二区三区| 庆余年2免费日韩剧观看大牛| 俺去了亚洲欧美日韩| 成人xvideos免费视频| 国产精品视频一区国模私拍| 久久久久久久色| 国产精品一区二区av影院萌芽| 中文字幕亚洲在线| 国产日韩在线观看av| 热门国产精品亚洲第一区在线| 国产这里只有精品| 国产一区二区动漫| 日韩视频中文字幕| 国产精品专区h在线观看| 国产精品视频在线播放| 成人做爰www免费看视频网站| 在线一区二区日韩| 91九色蝌蚪国产| 亚洲欧美在线一区二区| 亚洲理论片在线观看| 日韩亚洲综合在线| 国产一区二区三区视频免费| 精品国内产的精品视频在线观看| 韩国v欧美v日本v亚洲| 亚洲精品永久免费| 亚洲美女精品成人在线视频| 精品少妇v888av| 亚洲精品一区二区在线| 亚洲性无码av在线| 久久久成人的性感天堂| 亚洲性线免费观看视频成熟| 色99之美女主播在线视频| 国产精品一二三在线| 亚洲精品视频免费在线观看| 欧美丰满老妇厨房牲生活| 成人激情综合网| 欧美亚洲激情视频| 人人做人人澡人人爽欧美| 亚洲综合色av| 韩国三级日本三级少妇99| 韩剧1988免费观看全集| 国产精品偷伦视频免费观看国产| 69精品小视频| 国产成人综合一区二区三区| 欧美美女15p| 亚洲成人网在线| 77777少妇光屁股久久一区| 亚洲片在线资源| 欧美亚洲国产另类| 人人澡人人澡人人看欧美| 欧美福利小视频| 日韩免费在线播放| 97成人精品区在线播放| 国内精品美女av在线播放| 欧美另类精品xxxx孕妇| 伊人久久免费视频| 亚洲精品狠狠操| 欧美日韩激情视频| 欧美乱大交xxxxx另类电影| 成人有码在线播放| 亚洲网站在线看| 国产成人在线一区二区| 久久久久女教师免费一区| 亚洲社区在线观看| 国产精品6699| 日韩欧美亚洲范冰冰与中字| 亚洲va欧美va国产综合剧情| 国产一区在线播放| 国产999在线观看| 成人午夜激情免费视频| 亚洲精品一区av在线播放| 日韩欧美亚洲成人| 欧美性猛交视频| 欧美日韩高清区| 欧美亚洲激情视频| 国产精品网红直播| 亚洲国产一区二区三区四区| 久久人91精品久久久久久不卡| 国产91精品久久久久| 欧美成在线观看| 热久久视久久精品18亚洲精品| 欧美日韩国产中文字幕| 欧美激情免费视频| 国产精品自拍偷拍视频| 正在播放国产一区| 中文字幕久热精品在线视频| 精品久久久久国产| 欧洲成人午夜免费大片| 正在播放欧美一区| 国产精品1234| 亚洲欧洲在线播放| 成人欧美在线观看| 另类视频在线观看| 久久中文字幕国产| 久久伊人免费视频| 亚洲加勒比久久88色综合| 国产精品欧美在线| 欧洲成人免费视频| 日本亚洲欧洲色α| 日韩欧美在线观看| 成人国产精品一区二区| 国产精品久久77777| 精品亚洲一区二区三区在线播放| 亚洲女成人图区| 日韩精品视频在线观看免费| 97超级碰在线看视频免费在线看| 热门国产精品亚洲第一区在线| 国产精品女人久久久久久| 九九视频直播综合网| 最近2019年中文视频免费在线观看| 78m国产成人精品视频| 久久天天躁狠狠躁夜夜av| 国产欧美韩国高清| 国产一区二区三区高清在线观看| 亚洲伊人久久大香线蕉av| 97热精品视频官网| 亚洲欧美日韩中文视频| 国产网站欧美日韩免费精品在线观看| 亚洲一区二区三区视频播放| 中文字幕不卡av| 亚洲第一视频在线观看| 91精品免费久久久久久久久| 欧洲美女免费图片一区| 精品国产拍在线观看| 国产精品免费看久久久香蕉| 国产精品免费在线免费| 最近2019中文免费高清视频观看www99| 91精品国产91久久久久久不卡| 国产日韩在线免费|