最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

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

引言

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

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

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

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

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

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

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

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

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

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

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

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

1.2、執(zhí)行上下文

執(zhí)行上下文JavaScript中非常重要的概念,它代表了代碼執(zhí)行時(shí)的環(huán)境。每當(dāng)JavaScript引擎執(zhí)行一段代碼時(shí),都會創(chuàng)建一個(gè)執(zhí)行上下文。執(zhí)行上下文包含了三個(gè)重要的組成部分:變量對象、作用域鏈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)部的代碼都在全局上下文中。一個(gè)程序中只會有一個(gè)全局執(zhí)行上下文。

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

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

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

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

 小知識

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

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

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

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

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

3.1、創(chuàng)建階段

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

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

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

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

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

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

小知識

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

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

JavaScript中的作用域鏈?zhǔn)且粋€(gè)機(jī)制,決定了一段代碼對于代碼庫中其他一些代碼來說的可訪問性

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

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

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

小知識

作用域的概念就引出了JavaScript另一個(gè)相關(guān)的現(xiàn)象——閉包。閉包指的是內(nèi)部函數(shù)永遠(yuǎn)可以訪問外部函數(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對象。同時(shí),由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引擎就進(jìn)入到執(zhí)行階段。

3.2、執(zhí)行階段

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

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

3.3、銷毀階段

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

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

小知識

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

4、執(zhí)行棧

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

小知識

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

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

一旦活躍執(zhí)行上下文中的代碼被執(zhí)行完畢,JS引擎就會從執(zhí)行棧中彈出這個(gè)執(zhí)行上下文,緊接著執(zhí)行下一個(gè)執(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

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

4.2、圖示講解

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

當(dāng)JS引擎遇到first函數(shù)調(diào)用時(shí),一個(gè)新的FEC被創(chuàng)建。新的執(zhí)行上下文被放置在當(dāng)前上下文上方,形成執(zhí)行棧。在first函數(shù)調(diào)用時(shí),其執(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è)置一個(gè)新的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ù),這個(gè)執(zhí)行上下文從執(zhí)行棧上彈出。

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

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

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

相關(guān)文章

  • JS不間斷向上滾動效果代碼

    JS不間斷向上滾動效果代碼

    不間斷向上滾動的效果,想必大家都有見到過吧,本文也為大家準(zhǔn)備一個(gè)使用js實(shí)現(xiàn)的不間斷向上滾動效果,感興趣的朋友可以參考下
    2013-12-12
  • JS如何實(shí)現(xiàn)form表單登錄驗(yàn)證并使用MD5加密詳解

    JS如何實(shí)現(xiàn)form表單登錄驗(yàn)證并使用MD5加密詳解

    表單驗(yàn)證為終端用戶檢測無效的數(shù)據(jù)并標(biāo)記這些錯(cuò)誤,是一種用戶體驗(yàn)的優(yōu)化,下面這篇文章主要給大家介紹了關(guān)于JS如何實(shí)現(xiàn)form表單登錄驗(yàn)證并使用MD5加密的相關(guān)資料,需要的朋友可以參考下
    2023-06-06
  • 每天一篇javascript學(xué)習(xí)小結(jié)(Boolean對象)

    每天一篇javascript學(xué)習(xí)小結(jié)(Boolean對象)

    這篇文章主要介紹了javascript中的Boolean對象知識點(diǎn),對Boolean對象的基本使用方法進(jìn)行解釋,一段很詳細(xì)的代碼介紹,感興趣的小伙伴們可以參考一下
    2015-11-11
  • js控制li的隱藏和顯示實(shí)例代碼

    js控制li的隱藏和顯示實(shí)例代碼

    下面小編就為大家?guī)硪黄猨s控制li的隱藏和顯示實(shí)例代碼。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2016-10-10
  • 異步JS框架的作用以及實(shí)現(xiàn)方法

    異步JS框架的作用以及實(shí)現(xiàn)方法

    這篇文章主要介紹了異步JS框架的作用以及使用方法
    2015-10-10
  • 移動端界面的適配

    移動端界面的適配

    本文主要介紹了移動端頁面適配相關(guān)知識,用于解決在所有手機(jī)上看到字體的大小都一樣問題。下面跟著小編一起來看下吧
    2017-01-01
  • javascript中關(guān)于執(zhí)行環(huán)境的雜談

    javascript中關(guān)于執(zhí)行環(huán)境的雜談

    如你所知,javascript里執(zhí)行環(huán)境是作為一個(gè)最核心的概念存在的。相信廣大FE筒子們對于這個(gè)概念不會陌生,它定義了變量或函數(shù)有權(quán)訪問其他數(shù)據(jù)范圍以及其行為。
    2011-08-08
  • Python版實(shí)現(xiàn)微信公眾號掃碼登陸

    Python版實(shí)現(xiàn)微信公眾號掃碼登陸

    這篇文章主要介紹了Python版實(shí)現(xiàn)微信公眾號掃碼登陸,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-05-05
  • 使用webpack-dev-server處理跨域請求的方法

    使用webpack-dev-server處理跨域請求的方法

    本篇文章主要介紹了使用webpack-dev-server處理跨域請求的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-04-04
  • JavaScript解決Joseph問題

    JavaScript解決Joseph問題

    JavaScript解決Joseph問題...
    2007-02-02

最新評論

新平| 临桂县| 辛集市| 双城市| 宜兰市| 杭锦旗| 江达县| 九寨沟县| 烟台市| 河北省| 临泽县| 石林| 收藏| 沁源县| 大安市| 庐江县| 佳木斯市| 遂川县| 布拖县| 江达县| 克山县| 丹凤县| 阳西县| 江孜县| 亚东县| 平阴县| 内江市| 镇赉县| 泽库县| 余江县| 祁东县| 无锡市| 宁南县| 乐至县| 门头沟区| 霍城县| 辽源市| 天台县| 上虞市| 四子王旗| 来安县|