亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

詳解JavaScript中的執(zhí)行上下文

 更新時間:2023年07月27日 09:58:02   作者:歸子莫  
執(zhí)行上下文是JavaScript中非常重要的概念,它決定了代碼的執(zhí)行順序和作用域鏈等重要信息,下面我們就來深入探討JavaScript執(zhí)行上下文的概念和工作原理吧

引言

當(dāng)我們在瀏覽器中運行JavaScript代碼時,瀏覽器會先創(chuàng)建一個全局執(zhí)行上下文(Global Execution Context),然后逐行解析和執(zhí)行代碼。

執(zhí)行上下文是JavaScript中非常重要的概念,它決定了代碼的執(zhí)行順序和作用域鏈等重要信息。了解執(zhí)行上下文的概念和工作原理,對于理解JavaScript的運行機制和調(diào)試錯誤非常有幫助。

在本文中,我們將深入探討JavaScript的執(zhí)行上下文,從而幫助讀者更好地理解JavaScript的運行機制。

1、什么是執(zhí)行上下文

一般來說,聽到上下文這個東西,很自然想到了語文老師講到的在上下文中找到相關(guān)聯(lián)的段落和句子...

其實在JS中的上下文更多的是一個抽象的概念。它具體是指在當(dāng)前執(zhí)行環(huán)境中的變量、函數(shù)聲明,參數(shù)(arguments),作用域鏈,this等信息

1.1、瀏覽器如何理解執(zhí)行JavaScript

瀏覽器并不理解我們在應(yīng)用中編寫的高級JavaScript代碼。代碼需要被轉(zhuǎn)換成瀏覽器和計算機能夠理解的格式——機器碼。

瀏覽器在讀取HTML時,如果遇到了<script> 標(biāo)簽或包含JavaScript代碼的屬性如onClick,會發(fā)送給JavaScript引擎。

瀏覽器的JavaScript引擎會創(chuàng)造一個特殊的環(huán)境來處理這些JavaScript代碼的轉(zhuǎn)換和執(zhí)行。這個特殊的環(huán)境被稱為執(zhí)行上下文。

執(zhí)行上下文包含當(dāng)前正在運行的代碼和有助于其執(zhí)行的所有內(nèi)容。在執(zhí)行上下文運行期間,編譯器解析代碼,內(nèi)存存儲變量和函數(shù),可執(zhí)行的字節(jié)碼生成后,代碼執(zhí)行。

實在不好理解,先入為主,將之想象成一個執(zhí)行JS的容器。

1.2、執(zhí)行上下文

執(zhí)行上下文JavaScript中非常重要的概念,它代表了代碼執(zhí)行時的環(huán)境。每當(dāng)JavaScript引擎執(zhí)行一段代碼時,都會創(chuàng)建一個執(zhí)行上下文。執(zhí)行上下文包含了三個重要的組成部分:變量對象作用域鏈this值。

  • 變量對象:是當(dāng)前執(zhí)行上下文中的變量、函數(shù)聲明和函數(shù)參數(shù)的存儲空間。
  • 作用域鏈:是當(dāng)前執(zhí)行上下文中所有父級執(zhí)行上下文的變量對象的集合,它決定了當(dāng)前執(zhí)行上下文中變量的可訪問性。
  • this值:代表當(dāng)前函數(shù)的執(zhí)行環(huán)境。

2、執(zhí)行上下文有哪些類型呢

JavaScript中有三種執(zhí)行上下文類型

1.全局執(zhí)行上下文(GEC)

任何不在函數(shù)內(nèi)部的代碼都在全局上下文中。一個程序中只會有一個全局執(zhí)行上下文。

2.函數(shù)執(zhí)行上下文(FEC)

每當(dāng)一個函數(shù)被調(diào)用時, 都會為該函數(shù)創(chuàng)建一個新的上下文。每個函數(shù)都有它自己的執(zhí)行上下文,它在函數(shù)被調(diào)用時創(chuàng)建。函數(shù)上下文可以有任意多個。

3.Eval函數(shù)執(zhí)行上下文

執(zhí)行在eval函數(shù)內(nèi)部的代碼也會有它屬于自己的執(zhí)行上下文。eval不經(jīng)常被使用到。

 小知識

eval()函數(shù)計算JavaScript字符串,并把它作為腳本代碼來執(zhí)行。

如果參數(shù)是一個表達式,eval()函數(shù)將執(zhí)行表達式。如果參數(shù)是Javascript語句,eval()將執(zhí)行Javascript語句。

主要的還是全局執(zhí)行上下文函數(shù)執(zhí)行上下文

3、執(zhí)行上下文的生命周期

在JavaScript中,執(zhí)行上下文的生命周期可以分為三個階段:創(chuàng)建階段、執(zhí)行階段和銷毀階段。

3.1、創(chuàng)建階段

在創(chuàng)建階段,執(zhí)行上下文首先與執(zhí)行上下文對象(ECO)相關(guān)聯(lián)。執(zhí)行上下文對象存儲了許多重要的數(shù)據(jù),執(zhí)行上下文中的代碼在運行時會使用這些數(shù)據(jù)。創(chuàng)建階段分三個步驟來定義和設(shè)置執(zhí)行上下文對象的屬性:

  • 創(chuàng)建變量對象(VO
  • 創(chuàng)建作用域鏈
  • 設(shè)置this關(guān)鍵字的值

3.1.1、創(chuàng)建變量對象(VO)

變量對象(VO)是一個在執(zhí)行上下文中創(chuàng)建的類似于對象的容器,存儲執(zhí)行上下文中變量函數(shù)聲明。

GEC中,每當(dāng)使用var關(guān)鍵字聲明變量,VO就會添加一個指向該變量的屬性,并將值設(shè)置為undefined。每當(dāng)函數(shù)聲明時,VO就會添加一個指向該函數(shù)的屬性,并將這個屬性存儲在內(nèi)存中。這就意味著在開始運行代碼之前,所有函數(shù)聲明就已經(jīng)存儲在VO中,并可以在VO中訪問

但在FEC中并不創(chuàng)建VO,而是生成一個類數(shù)組對象,稱為arguments對象,在下文稱AO,包含傳入函數(shù)的所有參數(shù)。

小知識

這種將變量和函數(shù)聲明存儲在內(nèi)存中優(yōu)先于執(zhí)行代碼的過程被稱為提升。

3.1.2、創(chuàng)建作用域鏈

JavaScript中的作用域鏈是一個機制,決定了一段代碼對于代碼庫中其他一些代碼來說的可訪問性。

可以帶著這樣一些問題思考:

  • 一段代碼可以在哪里訪問?哪里不能訪問?
  • 代碼哪些部分可以被訪問?哪些部分不能?

每一個函數(shù)執(zhí)行上下文都會創(chuàng)建一個作用域,作用域相當(dāng)于是一個空間/環(huán)境,變量和函數(shù)定義在這個空間里,并且可以通過一個叫做作用域查找的過程訪問。如果函數(shù)被定義在另一個函數(shù)內(nèi)部,處在內(nèi)部的函數(shù)可以訪問自己內(nèi)部的代碼以及外部函數(shù)(父函數(shù))的代碼。這種行為被稱作詞法作用域查找。但外部函數(shù)并不能訪問內(nèi)部函數(shù)的代碼。

小知識

作用域的概念就引出了JavaScript另一個相關(guān)的現(xiàn)象——閉包。閉包指的是內(nèi)部函數(shù)永遠可以訪問外部函數(shù)中的代碼,即便外部函數(shù)已經(jīng)執(zhí)行完畢。

JavaScript引擎一路向上遍歷執(zhí)行上下文直至解析處在函數(shù)內(nèi)部觸發(fā)的變量和函數(shù)的概念就叫作用域鏈。

3.1.3、設(shè)置this關(guān)鍵字的值

JavaScriptthis關(guān)鍵字指的是執(zhí)行上下文所屬的作用域。一旦作用域鏈被創(chuàng)建,JS引擎就會初始化this關(guān)鍵字的值。

全局上下文中的this值:

GEC(所有函數(shù)和對象之外)中,this指向全局對象——window對象。同時,由var關(guān)鍵字初始化的函數(shù)聲明和變量會被作為全局對象(window對象)的方法或者屬性。

在任何函數(shù)外聲明的變量和函數(shù),如下:

var name = "jack"; 
function getName() { 
  console.log('hello') 
};

與下方的寫法是一致的:

window.name = "jack"; 
window.getName = () => { 
  console.log('hello') 
};

GEC中的函數(shù)和變量會被當(dāng)作window對象的方法和屬性。

函數(shù)中的this

FEC中,并沒有創(chuàng)建this對象,而是能夠訪問this被定義的環(huán)境。

在函數(shù)內(nèi)部訪問this的屬性,示例:

var msg = "hello world!"; 
function printMsg() { 
  console.log(this.msg); 
} 
printMsg(); // hello world!

小知識

在對象中,this關(guān)鍵字并不指向GEC,而是指向?qū)ο蟊旧怼?/p>

引用對象中的this如同引用:

對象.定義在對象內(nèi)部的屬性或方法;

示例代碼:

var msg = "hello world!"; 
const Obj = {
    msg = "no hello world!"; 
    printMsg() { console.log(this.msg); } 
}
Obj.printMsg(); // no hello world!

出現(xiàn)上述的情況,函數(shù)可以訪問的this關(guān)鍵字的值是定義其的對象Obj,而不是全局對象。

this關(guān)鍵字的值設(shè)置后,執(zhí)行上下文對象的所有屬性就定義完成,創(chuàng)建階段結(jié)束,JS引擎就進入到執(zhí)行階段。

3.2、執(zhí)行階段

執(zhí)行上下文創(chuàng)建階段之后就是執(zhí)行階段了,在這一階段代碼執(zhí)行真正開始。創(chuàng)建階段之后,VO包含的變量值為undefined,如果在此時運行代碼,肯定會報錯,因此JavaScript引擎無法執(zhí)行未定義的變量。

在執(zhí)行階段,JavaScript引擎會再次讀取執(zhí)行上下文,并用變量的實際值更新VO。編譯器再把代碼編譯為計算機可執(zhí)行的字節(jié)碼后執(zhí)行。如果在代碼執(zhí)行過程中發(fā)生異常,JavaScript引擎會拋出異常并停止執(zhí)行代碼。

3.3、銷毀階段

執(zhí)行上下文銷毀階段是指當(dāng)一個函數(shù)執(zhí)行完畢或者當(dāng)前執(zhí)行上下文被彈出執(zhí)行上下文棧時,執(zhí)行上下文會被銷毀的過程。在執(zhí)行上下文銷毀階段,JavaScript引擎會執(zhí)行以下步驟:

  • 垃圾回收JavaScript引擎會檢查當(dāng)前執(zhí)行上下文中的變量對象和函數(shù)聲明是否被其他對象引用。如果沒有被引用,則這些對象將被標(biāo)記為垃圾對象,并在垃圾回收過程中被清除。
  • 變量銷毀JavaScript引擎會銷毀當(dāng)前執(zhí)行上下文中的所有變量。在函數(shù)執(zhí)行結(jié)束時,所有局部變量將被銷毀。在全局執(zhí)行上下文中,全局變量只有在頁面關(guān)閉時才會被銷毀。
  • 閉包變量銷毀:如果當(dāng)前執(zhí)行上下文是一個閉包函數(shù),那么其中的閉包變量將不會被銷毀。這是因為閉包變量被外層函數(shù)的作用域鏈所引用,只有當(dāng)外層函數(shù)被銷毀時,閉包變量才會被銷毀。
  • 執(zhí)行上下文彈出JavaScript引擎會將當(dāng)前執(zhí)行上下文從執(zhí)行上下文棧中彈出,并將控制權(quán)返回給上一個執(zhí)行上下文。

小知識

ES5以上的規(guī)范,對于執(zhí)行上下文的創(chuàng)建過程有所調(diào)整,移除了了ES3中的變量對象VO和活動對象AO,引入了詞法環(huán)境組件LexicalEnvironment component) 和變量環(huán)境組件VariableEnvironment component)。

4、執(zhí)行棧

執(zhí)行棧又稱調(diào)用棧,記錄了腳本整個生命周期中生成的執(zhí)行上下文。

小知識

JavaScrip是單線程語言,也就是說它只能在同一時間執(zhí)行一項任務(wù)。因此,其他的操作、函數(shù)和事件發(fā)生時,執(zhí)行上下文也會被創(chuàng)建。由于單線程的特性,一個堆疊了執(zhí)行上下文的棧就會被創(chuàng)建,稱為執(zhí)行棧。

JS引擎會搜索代碼中被調(diào)用的函數(shù)。每一次函數(shù)被調(diào)用,一個新的FEC就會被創(chuàng)建,并被放置在當(dāng)前執(zhí)行上下文的上方。而執(zhí)行棧最頂部的執(zhí)行上下文會成為活躍執(zhí)行上下文,并且始終是JS引擎優(yōu)先執(zhí)行。

一旦活躍執(zhí)行上下文中的代碼被執(zhí)行完畢,JS引擎就會從執(zhí)行棧中彈出這個執(zhí)行上下文,緊接著執(zhí)行下一個執(zhí)行上下文,以此類推。

4.1、示例代碼

用一段代碼來描述執(zhí)行棧的流程

var name = "Guizimo";
function first() {
  var a = "Hi!";
  second();
  console.log(`${a} ${name}`);
}
function second() {
  var b = "Hey!";
  third();
  console.log(`$ ${name}`);
}
function third() {
  var c = "Hello!";
  console.log(`${c} ${name}`);
}
first();

執(zhí)行結(jié)果:

Hello! Guizimo
Hey! Guizimo
Hi! Guizimo

對于這個預(yù)料之中,但總感覺奇奇怪怪的結(jié)果...所以還是使用圖示來講解一下。

4.2、圖示講解

JS引擎加載腳本,創(chuàng)建GEC,并壓入執(zhí)行棧的最底部。name變量,first、secondthird函數(shù)在所有函數(shù)外部定義,所以位于GEC,并且被VO存儲。

當(dāng)JS引擎遇到first函數(shù)調(diào)用時,一個新的FEC被創(chuàng)建。新的執(zhí)行上下文被放置在當(dāng)前上下文上方,形成執(zhí)行棧。在first函數(shù)調(diào)用時,其執(zhí)行上下文變成活躍執(zhí)行上下文。在first函數(shù)中的變量a ='Hi!'被存儲在其FEC中,而非GEC中。

緊接著,second函數(shù)在first函數(shù)中被調(diào)用。由于JavaScript單線程的特性,first函數(shù)的執(zhí)行會被暫停,直到second函數(shù)執(zhí)行完閉,才會繼續(xù)執(zhí)行。同樣的,JS引擎會給second函數(shù)設(shè)置一個新的FEC,并把它放置在棧頂端,并激活。second函數(shù)成為活躍執(zhí)行上下文,變量b = 'Hey!'被存儲在其FEC中。

再之后second函數(shù)中的third函數(shù)被調(diào)用,其FEC被創(chuàng)建并放置在執(zhí)行棧的頂部。

third函數(shù)中的變量c = 'Hello!'被存儲在其FEC中,Hello! Guizimo在控制臺中打印。等待third函數(shù)執(zhí)行完畢后, 其FEC就從棧頂端彈出,而調(diào)用third函數(shù)的second函數(shù)重新成為活躍執(zhí)行上下文。

回到second函數(shù),控制臺打印Hey! Guizimo。函數(shù)執(zhí)行完成所有任務(wù),這個執(zhí)行上下文從執(zhí)行棧上彈出。

當(dāng)first函數(shù)執(zhí)行完畢,從執(zhí)行棧上彈出后,控制流回到代碼的GEC。

最終,所有代碼執(zhí)行完畢,JS引擎GEC從執(zhí)行棧上彈出。

以上就是詳解JavaScript中的執(zhí)行上下文的詳細內(nèi)容,更多關(guān)于JavaScript執(zhí)行上下文的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • ECharts柱狀排名圖柱子上方顯示文字與圖標(biāo)代碼實例

    ECharts柱狀排名圖柱子上方顯示文字與圖標(biāo)代碼實例

    我們在繪制柱狀圖時如果想要柱條上顯示文字,可以參考本文,這篇文章主要給大家介紹了關(guān)于ECharts柱狀排名圖柱子上方顯示文字與圖標(biāo)的相關(guān)資料,需要的朋友可以參考下
    2023-11-11
  • 微信小程序?qū)崿F(xiàn)動態(tài)獲取元素寬高的方法分析

    微信小程序?qū)崿F(xiàn)動態(tài)獲取元素寬高的方法分析

    這篇文章主要介紹了微信小程序?qū)崿F(xiàn)動態(tài)獲取元素寬高的方法,結(jié)合實例形式分析了微信小程序動態(tài)獲取、設(shè)置元素寬高的相關(guān)操作技巧與注意事項,需要的朋友可以參考下
    2018-12-12
  • 20分鐘成功編寫bootstrap響應(yīng)式頁面 就這么簡單

    20分鐘成功編寫bootstrap響應(yīng)式頁面 就這么簡單

    這篇文章主要教大家如何在20分鐘內(nèi)成功編寫bootstrap響應(yīng)式頁面,其實很簡單,培養(yǎng)大家分分鐘開發(fā)出一個高大上的頁面能力,感興趣的小伙伴們可以參考一下
    2016-05-05
  • JS實現(xiàn)水平遍歷和嵌套遞歸操作示例

    JS實現(xiàn)水平遍歷和嵌套遞歸操作示例

    這篇文章主要介紹了JS實現(xiàn)水平遍歷和嵌套遞歸操作,結(jié)合實例形式分析了javascript遍歷與遞歸相關(guān)操作技巧,需要的朋友可以參考下
    2019-08-08
  • Javascript和jQuery的深淺拷貝詳解

    Javascript和jQuery的深淺拷貝詳解

    這篇文章主要為大家詳細介紹了Javascript和jQuery的深淺拷貝,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • 微信小程序使用GoEasy實現(xiàn)websocket實時通訊

    微信小程序使用GoEasy實現(xiàn)websocket實時通訊

    這篇文章主要介紹了微信小程序使用GoEasy實現(xiàn)websocket實時通訊的方法,本文通過實例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-05-05
  • 第一篇初識bootstrap

    第一篇初識bootstrap

    Bootstrap是twitter的工程師在業(yè)余時間開發(fā)的,是一款目前非常流行的前端框架。本文給大家介紹第一篇初識bootstrap的相關(guān)知識,非常不錯具有參考借鑒價值,感興趣的朋友一起學(xué)習(xí)吧
    2016-06-06
  • 微信小程序和H5頁面間相互跳轉(zhuǎn)代碼實例

    微信小程序和H5頁面間相互跳轉(zhuǎn)代碼實例

    這篇文章主要介紹了微信小程序和H5頁面間相互跳轉(zhuǎn)代碼實例,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-09-09
  • javascript修改表格背景色實例代碼分享

    javascript修改表格背景色實例代碼分享

    這篇文章主要介紹了javascript修改表格背景色實例,代碼簡單,大家參考使用吧
    2013-12-12
  • JavaScript仿淘寶放大鏡效果

    JavaScript仿淘寶放大鏡效果

    這篇文章主要為大家詳細介紹了JavaScript仿淘寶放大鏡效果,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-10-10

最新評論