摘要:作用域和作用域鏈關(guān)于作用域這里不做過多解釋,中根據(jù)作用域可分為全局變量和局部變量。好吧,不是這部分核心,核心是解釋的單線程和事件輪詢機(jī)制。這部分就涉及到閉包的理解了。
題目描述前言:這是一道很經(jīng)典的Js面試題,涉及到閉包、變量作用域、setTimeout等知識(shí),對(duì)于深入理解這些內(nèi)容很有幫助
//問題描述:請(qǐng)寫出最終的輸出值,并解釋原因 var value1 = 0, value2 = 0, value3 = 0; for ( var i = 1; i <= 3; i++) { var i2 = i; (function() { var i3 = i; setTimeout(function() { value1 += i; value2 += i2; value3 += i3; }, 1); })(); } setTimeout(function() { console.log(value1, value2, value3); }, 100);
//輸出結(jié)果:value1=12; value2=9; value3=6題目解釋
首先,為了下面解釋這道題,我們先來補(bǔ)充一些預(yù)備知識(shí)(大神級(jí)人物可跳過這部分)
一、基礎(chǔ)知識(shí)補(bǔ)充與溫習(xí) 1、閉包和作用域官方解釋:所謂“閉包”,指的是一個(gè)擁有許多變量和綁定了這些變量的環(huán)境的表達(dá)式(通常是一個(gè)函數(shù)),因而這些變量也是該表達(dá)式的一部分。
function a(){ var i=0; function b(){ alert(++i); } return b; } var c=a(); c();
方言版:當(dāng)函數(shù)a的內(nèi)部函數(shù)b被外部變量c引用時(shí),就形成了閉包
閉包的作用:我們知道,js里定義在函數(shù)內(nèi)部的是局部變量,外部是無法直接訪問的,而它的內(nèi)部函數(shù)可以訪問,那么內(nèi)部函數(shù)返回一個(gè)值,就相當(dāng)于類似在外部也能訪問局部變量。
閉包的特點(diǎn):為了使b中能夠訪問i的值,i不會(huì)被內(nèi)存回收,就實(shí)現(xiàn)了內(nèi)存常駐。對(duì)于理解這道題很重要。
閉包的缺點(diǎn):內(nèi)部閉包函數(shù)可以訪問外部函數(shù)的變量,所以外部函數(shù)的變量不能被釋放,如果閉包嵌套過多,會(huì)導(dǎo)致內(nèi)存占用大,出現(xiàn)內(nèi)存溢出。
作用域和作用域鏈:關(guān)于作用域這里不做過多解釋,js中根據(jù)作用域可分為全局變量和局部變量。而對(duì)于作用域鏈的簡(jiǎn)單理解,可以認(rèn)為當(dāng)一個(gè)函數(shù)創(chuàng)建之后,從它的執(zhí)行環(huán)境(當(dāng)前對(duì)象)一直到全局對(duì)象建立了一個(gè)鏈表,可用的變量都掛載在上面。而函數(shù)需要查找某個(gè)變量值時(shí),變回按照從當(dāng)前直到全局對(duì)象來進(jìn)行查找。
2、事件輪詢與setTimeout簡(jiǎn)介:setTimeout是js中常見的一個(gè)函數(shù),屬于window下的方法(通常,大家會(huì)省略window)
語法:setTimeout(code,millisec) 參數(shù)一為代碼,參數(shù)二為毫秒數(shù)
作用:設(shè)定一個(gè)時(shí)間, 時(shí)間到了之后, 就會(huì)執(zhí)行一個(gè)指定的函數(shù)或表達(dá)式,且只執(zhí)行一次。
好吧,setTimeout不是這部分核心,核心是解釋js的單線程和事件輪詢機(jī)制。
我們知道,js是單線程的,也就是說所有的任務(wù)要排隊(duì)執(zhí)行。
在js中有同步和異步執(zhí)行——
同步執(zhí)行:是指前一個(gè)任務(wù)執(zhí)行完,然后下一個(gè)任務(wù)繼續(xù)執(zhí)行,都在主線程里。
異步執(zhí)行:則是把事情放進(jìn)“任務(wù)隊(duì)列”(或叫事件隊(duì)里),而不是在主線程中,它們通過事件輪詢(Event Loop)和回調(diào)來實(shí)現(xiàn)調(diào)入主線程執(zhí)行。
繼續(xù)回到setTimeout,語法里面的code就是異步執(zhí)行的部分。
關(guān)于setTimeout更詳細(xì)的內(nèi)容,可點(diǎn)擊這里學(xué)習(xí)setTimeout那些事
關(guān)于事件輪詢的學(xué)習(xí),請(qǐng)點(diǎn)擊這里理解事件輪詢
上面都是些基礎(chǔ)知識(shí),接下來進(jìn)入正題。
首先,我們拿到題目,要注意到第一個(gè)setTimeout里面匿名函數(shù),這部分其實(shí)是放在for循環(huán)之后才會(huì)執(zhí)行的,因?yàn)樗且粋€(gè)異步執(zhí)行的函數(shù),被放到了事件隊(duì)列里最后執(zhí)行。而且,每次setTimeout里面的函數(shù)執(zhí)行時(shí)可以近似理解為是一次實(shí)例化。
value1
在計(jì)算value1時(shí),需要用到i,這里涉及到作用域鏈的知識(shí),最內(nèi)層的函數(shù)沒有i的值,它會(huì)沿著鏈?zhǔn)浇Y(jié)構(gòu)一直向上查找,最終發(fā)現(xiàn)i是for循環(huán)執(zhí)行之后的值。此時(shí),i的循環(huán)完成,最后一次i++之后,i已經(jīng)變成了4。這樣,setTimeout執(zhí)行3次實(shí)例化,每次i的值是不變的,最終值為value1=4+4+4=12。
value2
類似于value1,在執(zhí)行setTimeout里的函數(shù)時(shí),需要找到i2的值,最終我們找到的是for循環(huán)到第三次時(shí)i2=i=3。(i2不會(huì)等于4,因?yàn)榈阶詈笠淮蝘++之后,已經(jīng)不會(huì)再進(jìn)入循環(huán)體了)。所以類似上面,value2的值是3+3+3=9。
value3
這部分就涉及到閉包的理解了。在循環(huán)過程中,通過立即執(zhí)行函數(shù)創(chuàng)建了閉包,每次i3都會(huì)被賦予當(dāng)次循環(huán)時(shí)i的值并保存,i3的值依次為1,2,3,最終value3=1+2+3=6。
以上為個(gè)人解釋,如有錯(cuò)誤,還望各位指正。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/86759.html
摘要:函數(shù)式編程前端掘金引言面向?qū)ο缶幊桃恢币詠矶际侵械闹鲗?dǎo)范式。函數(shù)式編程是一種強(qiáng)調(diào)減少對(duì)程序外部狀態(tài)產(chǎn)生改變的方式。 JavaScript 函數(shù)式編程 - 前端 - 掘金引言 面向?qū)ο缶幊桃恢币詠矶际荍avaScript中的主導(dǎo)范式。JavaScript作為一門多范式編程語言,然而,近幾年,函數(shù)式編程越來越多得受到開發(fā)者的青睞。函數(shù)式編程是一種強(qiáng)調(diào)減少對(duì)程序外部狀態(tài)產(chǎn)生改變的方式。因此,...
摘要:一言以蔽之,閉包,你就得掌握。當(dāng)函數(shù)記住并訪問所在的詞法作用域,閉包就產(chǎn)生了。所以閉包才會(huì)得以實(shí)現(xiàn)。從技術(shù)上講,這就是閉包。執(zhí)行后,他的內(nèi)部作用域并不會(huì)消失,函數(shù)依然保持有作用域的閉包。 網(wǎng)上總結(jié)閉包的文章已經(jīng)爛大街了,不敢說筆者這篇文章多么多么xxx,只是個(gè)人理解總結(jié)。各位看官瞅瞅就好,大神還希望多多指正。此篇文章總結(jié)與《JavaScript忍者秘籍》 《你不知道的JavaScri...
摘要:同步異步回調(diào)傻傻分不清楚。分割線上面主要講了同步和回調(diào)執(zhí)行順序的問題,接著我就舉一個(gè)包含同步異步回調(diào)的例子。同步優(yōu)先回調(diào)內(nèi)部有個(gè),第二個(gè)是一個(gè)回調(diào)回調(diào)墊底。異步也,輪到回調(diào)的孩子們回調(diào),出來執(zhí)行了。 同步、異步、回調(diào)?傻傻分不清楚。 大家注意了,教大家一道口訣: 同步優(yōu)先、異步靠邊、回調(diào)墊底(讀起來不順) 用公式表達(dá)就是: 同步 => 異步 => 回調(diào) 這口訣有什么用呢?用來對(duì)付面試的...
摘要:同步異步回調(diào)傻傻分不清楚。分割線上面主要講了同步和回調(diào)執(zhí)行順序的問題,接著我就舉一個(gè)包含同步異步回調(diào)的例子。同步優(yōu)先回調(diào)內(nèi)部有個(gè),第二個(gè)是一個(gè)回調(diào)回調(diào)墊底。異步也,輪到回調(diào)的孩子們回調(diào),出來執(zhí)行了。 同步、異步、回調(diào)?傻傻分不清楚。 大家注意了,教大家一道口訣: 同步優(yōu)先、異步靠邊、回調(diào)墊底(讀起來不順) 用公式表達(dá)就是: 同步 => 異步 => 回調(diào) 這口訣有什么用呢?用來對(duì)付面試的...
閱讀 2899·2021-09-22 15:20
閱讀 2969·2021-09-22 15:19
閱讀 3471·2021-09-22 15:15
閱讀 2409·2021-09-08 09:35
閱讀 2386·2019-08-30 15:44
閱讀 3015·2019-08-30 10:50
閱讀 3747·2019-08-29 16:25
閱讀 1598·2019-08-26 13:55