色综合图-色综合图片-色综合图片二区150p-色综合图区-玖玖国产精品视频-玖玖香蕉视频

您的位置:首頁技術(shù)文章
文章詳情頁

詳解JavaScript作用域 閉包

瀏覽:102日期:2023-10-19 15:57:58

JavaScript閉包,是JS開發(fā)工程師必須深入了解的知識。3月份自己曾撰寫博客《JavaScript閉包》,博客中只是簡單闡述了閉包的工作過程和列舉了幾個示例,并沒有去刨根問底,將其弄明白!

現(xiàn)在隨著對JavaScript更深入的了解,也剛讀完《你不知道的JavaScript(上卷)》這本書,所以乘機整理下,從底層和原理上去刨一下。

JavaScript并不具有動態(tài)作用域,它只有詞法作用域。詞法作用域是在寫代碼或者說定義時確定的,而動態(tài)作用域是在運行時確定的。了解閉包前,首先我們得知道什么是詞法作用域(作用域是由書寫代碼時函數(shù)聲明的位置來決定的)。

一、何為閉包

示例1:

function foo(){var a = 2;function bar(){console.log(a);}return bar;}var baz = foo();bzz(); //2

在foo()執(zhí)行后,通常認為垃圾回收機制會將foo()的整個內(nèi)部作用域都被銷毀;而閉包可以阻止這樣事情發(fā)生,讓其內(nèi)部作用域依然存在。因為bar()處于foo()內(nèi)部,它擁有涵蓋foo()作用域的閉包,使得該作用域能夠一直存活,以供bar()在之后任何時間進行引用。

bar()依然持有對該作用域的引用,而這個引用就叫作閉包。

簡言之:當函數(shù)可以記住并訪問所在的詞法作用域,即使函數(shù)是在當前詞法作用域之外執(zhí)行,這時就產(chǎn)生了閉包。

示例2:

無論使用何種方式對函數(shù)類型的值進行傳遞,當函數(shù)在別處被調(diào)用時都可以觀察到閉包。

function foo(){var a = 2;function baz(){console.log(a);}bar(baz);}function bar(fn){fn();// 這就是閉包}

示例3:

將一個內(nèi)部函數(shù)(timer)傳遞給setTimeout。timer具有涵蓋wait()作用域的閉包,保有對變量message的引用。

wait()執(zhí)行1000毫秒后,它的作用域并不會消失,timer依然保有wait()作用域的閉包。

function wait(message){setTimeout( function timer(){console.log(message);},1000);}wait('Hello,ligang');

示例4:

下述activator()具有涵蓋setupBot()作用域的閉包!

function setupBot(name, selector){$(selector).click(function activator(){console.log('Activating: '+ name);});}setupBot('Closure Bot 1', '#bot_1');setupBot('Closure Bot 2', '#bot_2');

二、循環(huán)和閉包

for(var i=1; i<=5; i++){setTimeout(function timer(){console.log(i);}, i*1000);}// 期望:每秒一次的頻率輸出1~5// 結(jié)果:每秒一次的頻率輸出五次6

先解釋一下:“i*1000”,5個定時分別在1s、2s、3s、4s、5s后執(zhí)行,并不是1s、3s、6s、10s、15s。也就是頻率為1s,不是每次間隔增加1s。如果去掉i寫成“1000”,會在for執(zhí)行完1s后直接輸出五次6。

回調(diào)函數(shù)在循環(huán)結(jié)束后才被執(zhí)行,因此輸出的是循環(huán)終止條件是i值。事實上,當定時器運行時即使每個迭代中執(zhí)行的是setTimeout(..., 0),所有的回調(diào)函數(shù)依然是在循環(huán)結(jié)束后才被執(zhí)行。

根據(jù)作用域的工作原理,盡管五個函數(shù)是在各個迭代中分別定義的,但是它們都被封閉在一個共享的全局作用域中,因此實際上只有一個i。

解決方案1:

for(var i=0; i<=5; i++){(function(j){setTimeout(function timer(){console.log(j);}, j*1000 );})(i);}// 結(jié)果:每秒一次的頻率輸出1~5

每個迭代都生成一個新的作用域,使得延遲函數(shù)的回調(diào)可以將新的作用封閉在每個迭代內(nèi)部,每個迭代中都會含有一個具有正確值的變量供我們訪問。

解決方案2(ES6):

for(var i=0; i<=5; i++){let j = i;setTimeout(function timer(){console.log(j);}, j*1000 );}// 結(jié)果:每秒一次的頻率輸出1~5for(let i=0; i<=5; i++){setTimeout(function timer(){console.log(i);}, i*1000 );}// 結(jié)果:每秒一次的頻率輸出五次6

三、模塊

模塊需要具備兩個必要條件:

(1)必須有外部的封閉函數(shù),該函數(shù)必須至少被調(diào)用一次(每次調(diào)用都會創(chuàng)建一個新的模塊實例)。

(2)封閉函數(shù)必須返回至少一個內(nèi)部函數(shù),這樣內(nèi)部函數(shù)才能在私有作用域中形成閉包,并且可以訪問或者修改私有的狀態(tài)。

典型的模塊化:

function CoolMoudle(){var something = 'cool';var doSomething = function(){console.log(something);}return{doSomething: doSomething};}var foo = CoolMoudle();//如果不執(zhí)行外部函數(shù)CoolMoudle(),內(nèi)部作用域和閉包都無法創(chuàng)建foo.doSomething();//cool

單例模式:

var foo = (function CoolModule(id){function change(){// 修改公共APIpublicAPI.identify = identify2;}function identify1(){console.log(id);}function identify2(){console.log(id.toUpperCase());}var publicAPI = {change: change,identify: identify1};return publicAPI;})('foo module');foo.identify();//foo modulefoo.change();foo.identify(); //FOO MODULE

以上就是詳解JavaScript作用域 閉包的詳細內(nèi)容,更多關(guān)于JavaScript作用域 閉包的資料請關(guān)注好吧啦網(wǎng)其它相關(guān)文章!

標簽: JavaScript
相關(guān)文章:
主站蜘蛛池模板: 久久久久久久久一级毛片 | 2020黄网| 亚洲欧美在线观看 | 亚洲一区天堂 | 日韩欧美在线观看视频 | 欧美成在线视频 | 亚洲精品久久久久影 | 一本久道久久综合婷婷五 | 欧美在线一级va免费观看 | 鲁大师成人精品视频 | 国产成人综合网亚洲欧美在线 | 欧美另类videosbestsex高清 | 男人把女人桶到喷白浆的视频 | 国产亚洲午夜精品a一区二区 | 久久精品视屏 | 国产精选91热在线观看 | 日本高清久久 | 日韩欧美一区二区三区在线 | 久久精品国产99国产精品 | 欧美国产日韩久久久 | 午夜影院黄色片 | 一级做a爰片久久毛片 | 欧美精品久久久久久久影视 | 亚洲国产天堂久久综合图区 | 久久网站在线观看 | 欧美大片一区二区三区 | 久久er视频| 自拍视频啪 | 一级做a爰片久久毛片 | 美女黄色在线 | 99精品久久精品一区二区 | 97视频免费播放观看在线视频 | 国产一区二区精品在线观看 | 就草草在线观看视频 | 日本a级特黄三级三级三级 日本a一级片 | 草草影院私人免费入口 | a级高清免费 | 性欧美高清极品xx | aaaa级毛片 | 国产女人自拍 | 五月天激激婷婷大综合蜜芽 |