執(zhí)行上下文/作用域鏈/閉包

  1. 對閉包的理解
    閉包是指有權(quán)訪問另一個(gè)函數(shù)作用域中變量的函數(shù)馋吗,創(chuàng)建閉包的最常見的方式就是在一個(gè)函數(shù)內(nèi)創(chuàng)建另一個(gè)函數(shù)焕盟,創(chuàng)建的函數(shù)可以訪問到當(dāng)前函數(shù)的局部變量。
    閉包有兩個(gè)常用的用途宏粤;

閉包的第一個(gè)用途是使我們在函數(shù)外部能夠訪問到函數(shù)內(nèi)部的變量脚翘。通過使用閉包,可以通過在外部調(diào)用閉包函數(shù)绍哎,從而在外部訪問到函數(shù)內(nèi)部的變量来农,可以使用這種方法來創(chuàng)建私有變量。
閉包的另一個(gè)用途是使已經(jīng)運(yùn)行結(jié)束的函數(shù)上下文中的變量對象繼續(xù)留在內(nèi)存中崇堰,因?yàn)殚]包函數(shù)保留了這個(gè)變量對象的引用沃于,所以這個(gè)變量對象不會(huì)被回收。

比如海诲,函數(shù) A 內(nèi)部有一個(gè)函數(shù) B繁莹,函數(shù) B 可以訪問到函數(shù) A 中的變量,那么函數(shù) B 就是閉包特幔。
function A() {
let a = 1
window.B = function () {
console.log(a)
}
}
A()
B() // 1
復(fù)制代碼
在 JS 中咨演,閉包存在的意義就是讓我們可以間接訪問函數(shù)內(nèi)部的變量。經(jīng)典面試題:循環(huán)中使用閉包解決 var 定義函數(shù)的問題
for (var i = 1; i <= 5; i++) {
setTimeout(function timer() {
console.log(i)
}, i * 1000)
}
復(fù)制代碼
首先因?yàn)?setTimeout 是個(gè)異步函數(shù)蚯斯,所以會(huì)先把循環(huán)全部執(zhí)行完畢薄风,這時(shí)候 i 就是 6 了,所以會(huì)輸出一堆 6拍嵌。解決辦法有三種:

第一種是使用閉包的方式

for (var i = 1; i <= 5; i++) { ;(function(j) { setTimeout(function timer() { console.log(j) }, j * 1000) })(i)}
復(fù)制代碼
在上述代碼中遭赂,首先使用了立即執(zhí)行函數(shù)將 i 傳入函數(shù)內(nèi)部,這個(gè)時(shí)候值就被固定在了參數(shù) j 上面不會(huì)改變撰茎,當(dāng)下次執(zhí)行 timer 這個(gè)閉包的時(shí)候嵌牺,就可以使用外部函數(shù)的變量 j,從而達(dá)到目的。

第二種就是使用 setTimeout 的第三個(gè)參數(shù)逆粹,這個(gè)參數(shù)會(huì)被當(dāng)成 timer 函數(shù)的參數(shù)傳入募疮。

for (var i = 1; i <= 5; i++) {
setTimeout(
function timer(j) {
console.log(j)
},
i * 1000,
i
)
}
復(fù)制代碼

第三種就是使用 let 定義 i 了來解決問題了,這個(gè)也是最為推薦的方式

for (let i = 1; i <= 5; i++) {
setTimeout(function timer() {
console.log(i)
}, i * 1000)
}
復(fù)制代碼

  1. 對作用域僻弹、作用域鏈的理解
    1)全局作用域和函數(shù)作用域
    (1)全局作用域

最外層函數(shù)和最外層函數(shù)外面定義的變量擁有全局作用域
所有未定義直接賦值的變量自動(dòng)聲明為全局作用域
所有window對象的屬性擁有全局作用域
全局作用域有很大的弊端阿浓,過多的全局作用域變量會(huì)污染全局命名空間,容易引起命名沖突蹋绽。

(2)函數(shù)作用域

函數(shù)作用域聲明在函數(shù)內(nèi)部的變零芭毙,一般只有固定的代碼片段可以訪問到
作用域是分層的,內(nèi)層作用域可以訪問外層作用域卸耘,反之不行

2)塊級作用域

使用ES6中新增的let和const指令可以聲明塊級作用域退敦,塊級作用域可以在函數(shù)中創(chuàng)建也可以在一個(gè)代碼塊中的創(chuàng)建(由{ }包裹的代碼片段)
let和const聲明的變量不會(huì)有變量提升,也不可以重復(fù)聲明
在循環(huán)中比較適合綁定塊級作用域蚣抗,這樣就可以把聲明的計(jì)數(shù)器變量限制在循環(huán)內(nèi)部侈百。

作用域鏈:
在當(dāng)前作用域中查找所需變量,但是該作用域沒有這個(gè)變量翰铡,那這個(gè)變量就是自由變量钝域。如果在自己作用域找不到該變量就去父級作用域查找,依次向上級作用域查找锭魔,直到訪問到window對象就被終止例证,這一層層的關(guān)系就是作用域鏈。
作用域鏈的作用是保證對執(zhí)行環(huán)境有權(quán)訪問的所有變量和函數(shù)的有序訪問迷捧,通過作用域鏈织咧,可以訪問到外層環(huán)境的變量和函數(shù)。
作用域鏈的本質(zhì)上是一個(gè)指向變量對象的指針列表党涕。變量對象是一個(gè)包含了執(zhí)行環(huán)境中所有變量和函數(shù)的對象烦感。作用域鏈的前端始終都是當(dāng)前執(zhí)行上下文的變量對象巡社。全局執(zhí)行上下文的變量對象(也就是全局對象)始終是作用域鏈的最后一個(gè)對象膛堤。
當(dāng)查找一個(gè)變量時(shí),如果當(dāng)前執(zhí)行環(huán)境中沒有找到晌该,可以沿著作用域鏈向后查找肥荔。

  1. 對執(zhí)行上下文的理解
  2. 執(zhí)行上下文類型
    (1)全局執(zhí)行上下文
    任何不在函數(shù)內(nèi)部的都是全局執(zhí)行上下文,它首先會(huì)創(chuàng)建一個(gè)全局的window對象朝群,并且設(shè)置this的值等于這個(gè)全局對象燕耿,一個(gè)程序中只有一個(gè)全局執(zhí)行上下文。
    (2)函數(shù)執(zhí)行上下文
    當(dāng)一個(gè)函數(shù)被調(diào)用時(shí)姜胖,就會(huì)為該函數(shù)創(chuàng)建一個(gè)新的執(zhí)行上下文誉帅,函數(shù)的上下文可以有任意多個(gè)。
    (3)eval函數(shù)執(zhí)行上下文
    執(zhí)行在eval函數(shù)中的代碼會(huì)有屬于他自己的執(zhí)行上下文,不過eval函數(shù)不常使用蚜锨,不做介紹档插。
  3. 執(zhí)行上下文棧

JavaScript引擎使用執(zhí)行上下文棧來管理執(zhí)行上下文
當(dāng)JavaScript執(zhí)行代碼時(shí),首先遇到全局代碼亚再,會(huì)創(chuàng)建一個(gè)全局執(zhí)行上下文并且壓入執(zhí)行棧中郭膛,每當(dāng)遇到一個(gè)函數(shù)調(diào)用,就會(huì)為該函數(shù)創(chuàng)建一個(gè)新的執(zhí)行上下文并壓入棧頂氛悬,引擎會(huì)執(zhí)行位于執(zhí)行上下文棧頂?shù)暮瘮?shù)则剃,當(dāng)函數(shù)執(zhí)行完成之后,執(zhí)行上下文從棧中彈出如捅,繼續(xù)執(zhí)行下一個(gè)上下文棍现。當(dāng)所有的代碼都執(zhí)行完畢之后,從棧中彈出全局執(zhí)行上下文镜遣。

let a = 'Hello World!';
function first() {
console.log('Inside first function');
second();
console.log('Again inside first function');
}
function second() {
console.log('Inside second function');
}
first();
//執(zhí)行順序
//先執(zhí)行second(),在執(zhí)行first()
復(fù)制代碼

  1. 創(chuàng)建執(zhí)行上下文
    創(chuàng)建執(zhí)行上下文有兩個(gè)階段:創(chuàng)建階段和執(zhí)行階段
    1)創(chuàng)建階段
    (1)this綁定

在全局執(zhí)行上下文中轴咱,this指向全局對象(window對象)
在函數(shù)執(zhí)行上下文中,this指向取決于函數(shù)如何調(diào)用烈涮。如果它被一個(gè)引用對象調(diào)用朴肺,那么 this 會(huì)被設(shè)置成那個(gè)對象,否則 this 的值被設(shè)置為全局對象或者 undefined

(2)創(chuàng)建詞法環(huán)境組件

詞法環(huán)境是一種有標(biāo)識(shí)符——變量映射的數(shù)據(jù)結(jié)構(gòu)坚洽,標(biāo)識(shí)符是指變量/函數(shù)名戈稿,變量是對實(shí)際對象或原始數(shù)據(jù)的引用。
詞法環(huán)境的內(nèi)部有兩個(gè)組件:加粗樣式:環(huán)境記錄器:用來儲(chǔ)存變量個(gè)函數(shù)聲明的實(shí)際位置外部環(huán)境的引用:可以訪問父級作用域

(3)創(chuàng)建變量環(huán)境組件

變量環(huán)境也是一個(gè)詞法環(huán)境讶舰,其環(huán)境記錄器持有變量聲明語句在執(zhí)行上下文中創(chuàng)建的綁定關(guān)系鞍盗。

2)執(zhí)行階段
此階段會(huì)完成對變量的分配,最后執(zhí)行完代碼跳昼。
簡單來說執(zhí)行上下文就是指:
在執(zhí)行一點(diǎn)JS代碼之前般甲,需要先解析代碼。解析的時(shí)候會(huì)先創(chuàng)建一個(gè)全局執(zhí)行上下文環(huán)境鹅颊,先把代碼中即將執(zhí)行的變量敷存、函數(shù)聲明都拿出來,變量先賦值為undefined堪伍,函數(shù)先聲明好可使用锚烦。這一步執(zhí)行完了,才開始正式的執(zhí)行程序帝雇。
在一個(gè)函數(shù)執(zhí)行之前涮俄,也會(huì)創(chuàng)建一個(gè)函數(shù)執(zhí)行上下文環(huán)境,跟全局執(zhí)行上下文類似尸闸,不過函數(shù)執(zhí)行上下文會(huì)多出this彻亲、arguments和函數(shù)的參數(shù)孕锄。

全局上下文:變量定義,函數(shù)聲明
函數(shù)上下文:變量定義苞尝,函數(shù)聲明硫惕,this,arguments

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末野来,一起剝皮案震驚了整個(gè)濱河市恼除,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌曼氛,老刑警劉巖豁辉,帶你破解...
    沈念sama閱讀 211,743評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異舀患,居然都是意外死亡徽级,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,296評論 3 385
  • 文/潘曉璐 我一進(jìn)店門聊浅,熙熙樓的掌柜王于貴愁眉苦臉地迎上來餐抢,“玉大人,你說我怎么就攤上這事低匙】鹾郏” “怎么了?”我有些...
    開封第一講書人閱讀 157,285評論 0 348
  • 文/不壞的土叔 我叫張陵顽冶,是天一觀的道長欺抗。 經(jīng)常有香客問我,道長强重,這世上最難降的妖魔是什么绞呈? 我笑而不...
    開封第一講書人閱讀 56,485評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮间景,結(jié)果婚禮上佃声,老公的妹妹穿的比我還像新娘。我一直安慰自己倘要,他們只是感情好圾亏,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,581評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著碗誉,像睡著了一般召嘶。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上哮缺,一...
    開封第一講書人閱讀 49,821評論 1 290
  • 那天,我揣著相機(jī)與錄音甲喝,去河邊找鬼尝苇。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的糠溜。 我是一名探鬼主播淳玩,決...
    沈念sama閱讀 38,960評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼非竿!你這毒婦竟也來了蜕着?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,719評論 0 266
  • 序言:老撾萬榮一對情侶失蹤红柱,失蹤者是張志新(化名)和其女友劉穎承匣,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體锤悄,經(jīng)...
    沈念sama閱讀 44,186評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡韧骗,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,516評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了零聚。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片袍暴。...
    茶點(diǎn)故事閱讀 38,650評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖隶症,靈堂內(nèi)的尸體忽然破棺而出政模,到底是詐尸還是另有隱情,我是刑警寧澤蚂会,帶...
    沈念sama閱讀 34,329評論 4 330
  • 正文 年R本政府宣布览徒,位于F島的核電站,受9級特大地震影響颂龙,放射性物質(zhì)發(fā)生泄漏习蓬。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,936評論 3 313
  • 文/蒙蒙 一措嵌、第九天 我趴在偏房一處隱蔽的房頂上張望躲叼。 院中可真熱鬧,春花似錦企巢、人聲如沸枫慷。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,757評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽或听。三九已至,卻和暖如春笋婿,著一層夾襖步出監(jiān)牢的瞬間誉裆,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,991評論 1 266
  • 我被黑心中介騙來泰國打工缸濒, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留足丢,地道東北人粱腻。 一個(gè)月前我還...
    沈念sama閱讀 46,370評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像斩跌,于是被迫代替她去往敵國和親绍些。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,527評論 2 349

推薦閱讀更多精彩內(nèi)容