這篇文章主要介紹“JavaScript執(zhí)行上下文與執(zhí)行棧是什么”的相關(guān)知識(shí),小編通過(guò)實(shí)際案例向大家展示操作過(guò)程,操作方法簡(jiǎn)單快捷,實(shí)用性強(qiáng),希望這篇“JavaScript執(zhí)行上下文與執(zhí)行棧是什么”文章能幫助大家解決問(wèn)題。
站在用戶的角度思考問(wèn)題,與客戶深入溝通,找到雙柏網(wǎng)站設(shè)計(jì)與雙柏網(wǎng)站推廣的解決方案,憑借多年的經(jīng)驗(yàn),讓設(shè)計(jì)與互聯(lián)網(wǎng)技術(shù)結(jié)合,創(chuàng)造個(gè)性化、用戶體驗(yàn)好的作品,建站類型包括:網(wǎng)站設(shè)計(jì)制作、成都網(wǎng)站制作、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣、域名與空間、雅安服務(wù)器托管、企業(yè)郵箱。業(yè)務(wù)覆蓋雙柏地區(qū)。
代碼執(zhí)行前,瀏覽器的Js
引擎先會(huì)創(chuàng)建代碼執(zhí)行的環(huán)境來(lái)處理此Js
代碼的轉(zhuǎn)換和執(zhí)行,代碼的執(zhí)行環(huán)境稱為執(zhí)行上下文。
執(zhí)行上下文是一個(gè)抽象概念,包含當(dāng)前正在運(yùn)行的代碼以及幫助其執(zhí)行的所有內(nèi)容。
執(zhí)行上下文主要分為三類:
全局執(zhí)行上下文 —— 全局代碼所處的環(huán)境,不在函數(shù)內(nèi)部代碼都在全局執(zhí)行。
函數(shù)執(zhí)行上下文 —— 在函數(shù)調(diào)用時(shí)創(chuàng)建的上下文。
Eval
執(zhí)行上下文 —— 運(yùn)行在Eval
函數(shù)中代碼時(shí)創(chuàng)建的環(huán)境,Eval
由于性能問(wèn)題在我們平時(shí)開發(fā)中很少用到,所有這里我們不在討論。
接下來(lái)我們重點(diǎn)來(lái)講全局上下文和函數(shù)上下文。
2.1 全局執(zhí)行上下文
當(dāng)我們的JS
文件跑起來(lái)之后,首先創(chuàng)建的就是全局執(zhí)行上下文。
當(dāng)我們的文件里沒(méi)有一行代碼時(shí),全局執(zhí)行上下文中比較干凈,只有兩個(gè)東西。
全局對(duì)象(瀏覽器里是Window
,Node
環(huán)境下是Global
)
this
變量(指向的還是全局對(duì)象)
這時(shí)候如果我們?cè)谖募飳扅c(diǎn)東西,比如我寫如下代碼:
var name = '小明'
var age = 18
function showName(){
return {
name : name,
age : age
}
}
全局執(zhí)行上下文就會(huì)立刻變成這個(gè)樣子:
上圖可以看到,我們明明給name
和age
賦值了,咋還會(huì)顯示undefined
呢?這是因?yàn)閳?zhí)行上下文分為兩部分,創(chuàng)建階段和執(zhí)行階段。
創(chuàng)建階段 —— 執(zhí)行上下文的初始化狀態(tài),做一些準(zhǔn)備工作
執(zhí)行階段 —— 代碼一行一行執(zhí)行
以上就是創(chuàng)建階段的全局上下文概況,在創(chuàng)建階段JS
引擎將會(huì)做以下幾件事:
將window
作為全局執(zhí)行上下文對(duì)象
創(chuàng)建this
,this
指向window
給變量和函數(shù)安排內(nèi)存空間
變量賦值undefined
,函數(shù)聲明放入內(nèi)存
放入作用域鏈
接下來(lái)才會(huì)進(jìn)入了全局執(zhí)行上下文的執(zhí)行階段,也就是賦值階段,如下圖:
需要注意的是執(zhí)行上下文執(zhí)行階段是一行一行執(zhí)行的,如下圖所示:
2.2 函數(shù)執(zhí)行上下文
理解完全局執(zhí)行上下文,函數(shù)執(zhí)行上下文也我們只需要關(guān)注它與全局上下文之間的不同即可,兩者之間不同主要表現(xiàn)在以下三個(gè)方面:
創(chuàng)建時(shí)機(jī):全局執(zhí)行上下文在執(zhí)行JS文件之前就被創(chuàng)建,而函數(shù)執(zhí)行上下文則是在函數(shù)調(diào)用時(shí)創(chuàng)建。
創(chuàng)建頻率:全局上下文在代碼剛開始被執(zhí)行前創(chuàng)建一次,而函數(shù)執(zhí)行上下文由腳本里函數(shù)調(diào)用次數(shù)決定,可以創(chuàng)建無(wú)數(shù)次。
創(chuàng)建內(nèi)容:全局執(zhí)行上下文將window
作為全局對(duì)象,而是函數(shù)執(zhí)行上下文則是創(chuàng)建參數(shù)對(duì)象arguments
;創(chuàng)建的this
也不會(huì)指向全局對(duì)象,而是取決于函數(shù)是如何調(diào)用的。
我們通過(guò)下面這個(gè)例子來(lái)看函數(shù)上下文不同階段的表現(xiàn):
var name = '小明'
var age = 18
function showName(){
return {
name : name,
age : age
}
}
// 調(diào)用該函數(shù)
showName()
當(dāng)我們調(diào)用showName
函數(shù)時(shí),就會(huì)進(jìn)入到函數(shù)執(zhí)行上下文的創(chuàng)建階段,函數(shù)執(zhí)行上下文的場(chǎng)景如下:
接著就會(huì)進(jìn)入到執(zhí)行階段,這個(gè)階段函數(shù)內(nèi)代碼才會(huì)一行一行執(zhí)行,這個(gè)例子中,因?yàn)闆](méi)有涉及到變量的修改,因此函數(shù)上下文的內(nèi)容保持不變,執(zhí)行完畢后,函數(shù)上下文的生命周期就結(jié)束了。
當(dāng)我們調(diào)用showName
函數(shù)時(shí),在瀏覽器中運(yùn)行狀況:
我們看到當(dāng)函數(shù)執(zhí)行完后,其對(duì)應(yīng)的執(zhí)行上下文也隨之消失了。這個(gè)消失的過(guò)程,我們叫它出?!?code>JS代碼執(zhí)行過(guò)程中,JS
引擎會(huì)為我們創(chuàng)建“執(zhí)行上下文棧”。
在全局代碼執(zhí)行前,JS
引擎為了管理執(zhí)行上下文,確保程序的執(zhí)行順序。JS
引擎會(huì)創(chuàng)建一個(gè)棧來(lái)管理所有的所有的執(zhí)行上下文對(duì)象。
因?yàn)楹瘮?shù)上下文可能會(huì)存在多個(gè),我們不可能保留所有的上下文。當(dāng)一個(gè)函數(shù)執(zhí)行完畢,其對(duì)應(yīng)的上下文必須讓出之前所占用的資源。因此上下文的建立和銷毀,就對(duì)應(yīng)了一個(gè)” 入棧 “和” 出棧 “的操作。
當(dāng)我們調(diào)用一個(gè)函數(shù)的時(shí)候,就會(huì)把它的上下文推入調(diào)用棧里,執(zhí)行完畢后出棧,隨后再為新的函數(shù)進(jìn)行入棧操作。
我們通過(guò)一個(gè)例子來(lái)看一下這個(gè)過(guò)程:
function testA(){
console.log('執(zhí)行第一個(gè)測(cè)試函數(shù)的邏輯');
testB();
console.log('再次執(zhí)行第一個(gè)測(cè)試函數(shù)的邏輯');
}
function testB(){
console.log('執(zhí)行第二個(gè)測(cè)試函數(shù)的邏輯');
}
testA()
1、執(zhí)行之前,全局上下文創(chuàng)建:
2、testA
調(diào)用,testA
對(duì)應(yīng)函數(shù)上下文創(chuàng)建:
3、testB
調(diào)用,testB
對(duì)應(yīng)函數(shù)上下文創(chuàng)建:
4、testB
執(zhí)行完畢,對(duì)應(yīng)上下文出棧,剩下testA
和全局執(zhí)行上下文:
5、testA
執(zhí)行完畢,對(duì)應(yīng)執(zhí)行上下文出棧,此時(shí)只剩下全局上下文:
在這整個(gè)過(guò)程里,調(diào)用棧的變化示意如下:
關(guān)于“JavaScript執(zhí)行上下文與執(zhí)行棧是什么”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí),可以關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,小編每天都會(huì)為大家更新不同的知識(shí)點(diǎn)。