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

js 執(zhí)行上下文和作用域的相關(guān)總結(jié)

 更新時間:2021年02月08日 11:56:26   作者:前端Serendipity  
這篇文章主要介紹了js 執(zhí)行上下文和作用域的相關(guān)知識總結(jié),幫助大家更好的理解和使用JavaScript,感興趣的朋友可以了解下

前言

  如果你是或者你想成為一名合格的前端開發(fā)工作者,你必須知道JavaScript代碼在執(zhí)行過程,知道執(zhí)行上下文、作用域、變量提升等相關(guān)概念,并且熟練應(yīng)用到自己的代碼中。本文參考了你不知道的JavaScript,和JavaScript高級程序設(shè)計(jì),以及部分博客。

正文

     1.JavaScript代碼的執(zhí)行過程相關(guān)概念

  js代碼的執(zhí)行分為編譯器的編譯和js引擎與作用域執(zhí)行兩個階段,其中編譯器編譯的階段(預(yù)編譯階段)分為分詞/詞法分析、解析/語法分析、代碼生成三個階段?!     ?/p>

     (1)在分詞/詞法分析階段,編譯器負(fù)責(zé)將代碼進(jìn)行分割處理,將語句分割成詞法單元流/數(shù)組;

    ?。?)在解析/詞法分析階段,將上一階段的詞法單元流轉(zhuǎn)換成由元素嵌套組成的符合程序語法結(jié)構(gòu)的抽象語法樹;

     (3)在代碼生成階段,將抽象語法樹轉(zhuǎn)換成可執(zhí)行代碼,并交付給js引擎。

   js代碼執(zhí)行的三個重要角色:

   ?。?)js引擎:負(fù)責(zé)代碼執(zhí)行的整個過程

   ?。?)編譯器:負(fù)責(zé)js代碼語法解析和生成可執(zhí)行代碼

   ?。?)作用域:手機(jī)并維護(hù)所有聲明標(biāo)識符,根據(jù)特定規(guī)則確定當(dāng)前代碼對聲明的標(biāo)識符的訪問權(quán)限

   2. 執(zhí)行上下文和執(zhí)行棧

  每當(dāng)js代碼在運(yùn)行的時候,它都是在執(zhí)行上下文中運(yùn)行。說到執(zhí)行上下文,需要知道什么時執(zhí)行棧,執(zhí)行棧,就是其他編程語言中的“調(diào)用?!保且环N擁有LIFO(后進(jìn)先出)數(shù)據(jù)結(jié)構(gòu)的棧,被用來存儲代碼運(yùn)行時所創(chuàng)建的執(zhí)行上下文。當(dāng)js引擎第一次遇到要執(zhí)行的代碼的時候,首先會創(chuàng)建一個全局的執(zhí)行上下文并壓入當(dāng)前執(zhí)行棧,每當(dāng)引擎遇到一個函數(shù)調(diào)用,它會為該函數(shù)創(chuàng)建一個新的執(zhí)行上下文并壓入棧頂,js引擎執(zhí)行棧頂?shù)暮瘮?shù),當(dāng)該函數(shù)執(zhí)行完畢,執(zhí)行上下文從棧中彈出,控制流程到達(dá)下一個上下文。對于每一個執(zhí)行上下文都含有三個重要屬性:變量對象,作用域鏈,this。這些屬性也需要徹底理解。

  2.1 、上下文調(diào)用棧

var scope1 = "global scope";
 function checkscope1(){
 var scope1 = "local scope";
 function f(){
 console.log(scope1); 
 }
 return f();
 }
 checkscope1();
var scope2 = "global scope";
 function checkscope2(){
 var scope2 = "local scope";
 function f(){
 console.log(scope2);
 }
 return f;
 }
 checkscope2()();

  上面兩段代碼都會輸出 local scope

    上面代碼中scope一定是局部變量,查找塊級作用域即可,不管何時何地執(zhí)行 f(),這種綁定在執(zhí)行f()時依然有效。出現(xiàn)了一樣的結(jié)果,但是兩段代碼的執(zhí)行上下文棧的變化不一樣 :

  第一段代碼:push(<checkscope1>functionContext)=>push(<f>functionContext)=>pop()=>pop()

    第二段代碼:push(<checkscope2>functionContext)=>pop()=>push(<f>functionContext)=>pop()

  2.2 、三種執(zhí)行上下文類型

  (1)全局上下文

    js引擎開始解析js代碼的時候首先遇到的就是全局代碼,初始化的時候會在調(diào)用棧中壓入一個全局執(zhí)行的上下文,當(dāng)整個應(yīng)用程序結(jié)束的時候才會清空執(zhí)行上下文棧,棧的最底部永遠(yuǎn)時全局執(zhí)行上下文。這是默認(rèn)的或者說基礎(chǔ)的全局作用域,任何函數(shù)內(nèi)部的代碼都在全局作用域中,首先創(chuàng)建一個全局的window對象,然后設(shè)置this的值等于這個全局對象,一個程序中只有一個全局執(zhí)行上下文。在頂層js代碼中可以使用this引用全局對象,因?yàn)槿謱ο髸r是域鏈的頭,意味著所有非限定性的變量和函數(shù)都作為該對象的函數(shù)來查詢。

    總之,全局執(zhí)行上下文只有一個,在客戶端中一般由瀏覽器創(chuàng)建,也就是我們熟知的window對象,我們能通過this直接訪問到它。

  (2)函數(shù)上下文

    每當(dāng)一個函數(shù)被調(diào)用是,都會外該函數(shù)創(chuàng)建一個新的上下文,每個函數(shù)都擁有自己的上下文,不過是在函數(shù)調(diào)用的時候創(chuàng)建的,需要注意的是同一個函數(shù)被多次調(diào)用,都會創(chuàng)建一個新的上下文。

  (3)eval和with上下文

    執(zhí)行在 eval和with 函數(shù)內(nèi)部的代碼也會有它屬于自己的執(zhí)行上下文,但由于 JavaScript 開發(fā)者并不經(jīng)常使用 eval,所以在這里我不會討論它。

  2.3 、執(zhí)行上下文創(chuàng)建階段

    執(zhí)行上下文創(chuàng)建分為創(chuàng)建階段與執(zhí)行階段兩個階段

    js引擎在執(zhí)行上下文創(chuàng)建階段主要負(fù)責(zé)三件事:確定this==>創(chuàng)建詞法環(huán)境組件==>創(chuàng)建變量環(huán)境組件(目前還不太理解)

    (1)確定this,這個不做詳解

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

    詞法環(huán)境是一種規(guī)范類型,基于 ECMAScript 代碼的詞法嵌套結(jié)構(gòu)來定義標(biāo)識符和具體變量和函數(shù)的關(guān)聯(lián)。一個詞法環(huán)境由環(huán)境記錄器和一個可能的引用外部詞法環(huán)境的空值組成。其中環(huán)境記錄用于存儲當(dāng)前環(huán)境中的變量和函數(shù)聲明的實(shí)際位置;外部環(huán)境引入記錄很好理解,它用于保存自身環(huán)境可以訪問的其它外部環(huán)境,那么說到這個,是不是有點(diǎn)作用域鏈的意思?

    詞法環(huán)境有兩種類型:

  • 全局環(huán)境(在全局執(zhí)行上下文中)是沒有外部環(huán)境引用的詞法環(huán)境。全局環(huán)境的外部環(huán)境引用是 null。它擁有內(nèi)建的 Object/Array/等、在環(huán)境記錄器內(nèi)的原型函數(shù)(關(guān)聯(lián)全局對象,比如 window 對象)還有任何用戶定義的全局變量,并且 this的值指向全局對象。
  • 在函數(shù)環(huán)境中,函數(shù)內(nèi)部用戶定義的變量存儲在環(huán)境記錄器中。并且引用的外部環(huán)境可能是全局環(huán)境,或者任何包含此內(nèi)部函數(shù)的外部函數(shù)。

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

    變量環(huán)境可以說也是詞法環(huán)境,它具備詞法環(huán)境所有屬性,一樣有環(huán)境記錄與外部環(huán)境引入。在ES6中唯一的區(qū)別在于詞法環(huán)境用于存儲函數(shù)聲明與let const聲明的變量,而變量環(huán)境僅僅存儲var聲明的變量。

   3. JavaScript作用域和作用域鏈

  3.1、作用域

  詞法作用域是在寫代碼或者定義的時候確定的,而動態(tài)作用域是在運(yùn)行時確定的,(this也是)詞法作用域關(guān)注函數(shù)在何處聲明,而動態(tài)作用域關(guān)注函數(shù)從何處調(diào)用,JavaScript采用詞法作用域,其作用域由你在寫代碼是將變量和塊作用域?qū)懺谀睦餂Q定,因此當(dāng)詞法分析器處理代碼時會保持作用域不變。可以理解為作用域就是一個獨(dú)立的地盤,讓變量不會外泄、暴露出去。也就是說作用域最大的用處就是隔離變量,不同作用域下同名變量不會有沖突。

  理解作用域之前先來看一道題

function foo() {
 console.log(value);
 }
 var value = 1;
 function bar() {
 var value = 2;
 console.log(value);
 foo();
 }
 bar();

  上面的代碼會輸出什么呢,首先在全局上下文中聲明foo()函數(shù)、value變量(其值為undefined)、bar()函數(shù),代碼執(zhí)行階段,bar函數(shù)上下文入棧并執(zhí)行,打印出value為2,然后執(zhí)行foo(),foo()入棧,打印value時找不到該變量,js引擎會查找上層作用域,即全局作用域,于是打印出1。后面函數(shù)執(zhí)行完畢上下文出棧。再來看下面這個函數(shù),作用域是分層的,內(nèi)層作用域可以訪問外層作用域的變量,反之則不行。

  ES6以來,js中的作用域分為全局作用域,函數(shù)作用域,塊級作用域和欺騙作用域。

  3.1.1、全局作用域

  在代碼中任何地方都能訪問到的對象擁有全局作用域,最外層函數(shù)和在最外層函數(shù)外面定義的變量擁有全局作用域,所有末定義直接賦值的變量自動聲明為擁有全局作用域。

  3.1.2、函數(shù)作用域

  函數(shù)作用域的含義是指,屬于這個函數(shù)的全部變量都可以在整個函數(shù)的范圍內(nèi)使用及復(fù)用(事實(shí)上在嵌套的作用域中也可以使用);
      這個原則是指在軟件設(shè)計(jì)中,應(yīng)該最小限度地暴露必 要內(nèi)容,而將其他內(nèi)容都“隱藏”起來;
      函數(shù)表達(dá)式可以是匿名的, 而函數(shù)聲明則不可以省略函數(shù)名。
  3.1.3、塊作用域
  塊作用域,通常指 { .. } 內(nèi)部
        (1)if 、 try/catch創(chuàng)建塊作用域;
        (2)let 關(guān)鍵字可以將變量綁定到所在的任意作用域中(通常是 { .. } 內(nèi)部);
        (3)for 循環(huán)頭部的 let 不僅將 i 綁定到了 for 循環(huán)的塊中,事實(shí)上它將其重新綁定到了循環(huán)的每一個迭代中,確保使用上一個循環(huán)迭代結(jié)束時的值重新進(jìn)行賦值;
        (4)const同樣可以用來創(chuàng)建塊作用域變量,但其值是固定的 (常量)。創(chuàng)建對象時值可以被改變。
  3.1.4、欺騙詞法作用域的方法,eval()和with()
    eval()參數(shù)為一個字符串,并把里面的內(nèi)容當(dāng)作書寫在該位置的代碼一樣處理(非嚴(yán)格模式);
   with()當(dāng)需要重復(fù)引用一個對象的多個屬性時,可以不需要重復(fù)引用對象本身。

  3.2、作用域鏈

    作用域鏈本質(zhì)上就是根據(jù)名稱查找變量(標(biāo)識符名稱)的一套規(guī)則。規(guī)則非常簡單,在自己的變量對象里找不到變量,就上父級的變量對象查找,當(dāng)?shù)诌_(dá)最外層的全局上下文中,無論找到還是沒找到,查找過程都會停止。查找會在找到第一個匹配的變量時停止,被稱為遮蔽效應(yīng)

   作用域鏈的用途是保證對執(zhí)行環(huán)境有權(quán)訪問的所有變量和函數(shù)的有序訪問                              
        作用域鏈:當(dāng)函數(shù)定義時,系統(tǒng)生成([scope])屬性,該屬性保存該函數(shù)的作用域鏈,該作用域鏈的第0位存儲當(dāng)前環(huán)境下的全局執(zhí)行期上下文GO,GO里存儲全局下的所有對象,其中包含函數(shù)和全局變量,當(dāng)函數(shù)執(zhí)行的前一刻,預(yù)編譯的時候,作用域鏈的頂端(第0位)存儲函數(shù)生成的執(zhí)行上下文AO,同時第一位存儲GO
        查找變量是到函數(shù)存儲的作用域鏈中從頂端開始依次向下查找(函數(shù)內(nèi)部作用域在最頂端,證明了函數(shù)可以訪問外部的變量,而外部無法訪問函數(shù)內(nèi)部的變量)

  4.執(zhí)行上下文和作用域的區(qū)別

  每個函數(shù)調(diào)用都有與之相關(guān)的作用域和上下文。從根本上說,范圍是基于函數(shù)(function-based)而上下文是基于對象(object-based)。換句話說, 作用域是和每次函數(shù)調(diào)用時變量的訪問有關(guān),并且每次調(diào)用都是獨(dú)立的。上下文總是關(guān)鍵字 this 的值,是調(diào)用當(dāng)前可執(zhí)行代碼的對象的引用。作用域是函數(shù)定義的時候就確定好的了,函數(shù)當(dāng)中的變量是和函數(shù)所處的作用域有關(guān),函數(shù)運(yùn)行的作用域也是與該函數(shù)定義時的作用域有關(guān)。而上下文,主要是關(guān)鍵字this的值,這個是由函數(shù)運(yùn)行時決定的,簡單來說就是誰調(diào)用此函數(shù),this就指向誰。

  5.最后

以上就是js 執(zhí)行上下文和作用域的相關(guān)總結(jié)的詳細(xì)內(nèi)容,更多關(guān)于js 執(zhí)行上下文和作用域的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評論