亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專(zhuān)欄INFORMATION COLUMN

[譯]了解Javascript中的執(zhí)行上下文和執(zhí)行堆棧

qujian / 3052人閱讀

摘要:理解執(zhí)行上下文和執(zhí)行堆棧對(duì)于理解的其它概念如提升,范圍和閉包至關(guān)重要。正確地理解執(zhí)行上下文和執(zhí)行堆棧將幫助你更好地使用開(kāi)發(fā)應(yīng)用。引擎執(zhí)行位于執(zhí)行堆棧頂部的方法。當(dāng)調(diào)用時(shí),為該函數(shù)創(chuàng)建一個(gè)新的執(zhí)行上下文,并且把它推入到當(dāng)前執(zhí)行堆棧。

By Sukhjinder Arora | Aug 28, 2018

原文

如果你是或者你想要成為一名js開(kāi)發(fā)者,那么你必須了解js程序內(nèi)部的運(yùn)作。理解執(zhí)行上下文和執(zhí)行堆棧對(duì)于理解js的其它概念(如提升,范圍和閉包)至關(guān)重要。

正確地理解執(zhí)行上下文和執(zhí)行堆棧將幫助你更好地使用js開(kāi)發(fā)應(yīng)用。

廢話(huà)少說(shuō),讓我們開(kāi)始吧:)

*

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

簡(jiǎn)單來(lái)說(shuō),執(zhí)行上下文是預(yù)估和執(zhí)行當(dāng)前環(huán)境下js代碼的抽象概念。每當(dāng)在js中運(yùn)行代碼時(shí),它都在執(zhí)行上下文中運(yùn)行。

(譯者:emmm,就是執(zhí)行上下文包含了追蹤當(dāng)前正在執(zhí)行的代碼的全部狀態(tài)。)

執(zhí)行上下文的類(lèi)型

在js中有三種執(zhí)行類(lèi)型

全局執(zhí)行上下文——這是默認(rèn)或者說(shuō)基礎(chǔ)執(zhí)行上下文。函數(shù)外的代碼就處于全局執(zhí)行上下文中。它做了兩件事:它創(chuàng)建了window對(duì)象(在瀏覽器環(huán)境下),也就是全局對(duì)象。并把this指向全局對(duì)象。在程序里面只能有一個(gè)全局上下文。

函數(shù)執(zhí)行上下文——每次函數(shù)被調(diào)用,都會(huì)為這個(gè)函數(shù)創(chuàng)建一個(gè)新的上下文。每個(gè)函數(shù)都有自己的上下文,但是只有被調(diào)用的時(shí)候才會(huì)被創(chuàng)建??梢杂泻芏鄠€(gè)函數(shù)執(zhí)行上下文。每當(dāng)創(chuàng)建一個(gè)新的函數(shù)執(zhí)行上下文,js引擎都會(huì)按照定義好的順序執(zhí)行一系列的步驟,我將會(huì)在下文中討論。

Eval 函數(shù)的執(zhí)行上下文——eval函數(shù)執(zhí)行的時(shí)候也會(huì)為它里面的代碼創(chuàng)建上下文,但是這個(gè)方法用的少,在本文略過(guò)。

執(zhí)行堆棧

執(zhí)行堆棧在其它語(yǔ)言中被稱(chēng)為“調(diào)用?!?,是一種先進(jìn)后出的一種數(shù)據(jù)結(jié)構(gòu),在代碼執(zhí)行期間被用于存儲(chǔ)所有的執(zhí)行上下文。

當(dāng)js引擎開(kāi)始解析js代碼時(shí),會(huì)先創(chuàng)建全局執(zhí)行上下文并且放在當(dāng)前執(zhí)行堆棧中。每當(dāng)引擎遇到函數(shù)調(diào)用的代碼時(shí),都會(huì)創(chuàng)建該函數(shù)的上下文并推入當(dāng)前執(zhí)行堆棧中。

引擎執(zhí)行位于執(zhí)行堆棧頂部的方法。當(dāng)方法執(zhí)行完畢,執(zhí)行堆棧pop掉最頂部的上下文,接著引擎繼續(xù)執(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();
console.log("Inside Global Execution Context");

上述代碼的執(zhí)行上下文堆棧。

當(dāng)上述代碼在瀏覽器內(nèi)加載,js引擎就會(huì)創(chuàng)建一個(gè)全局執(zhí)行上下文并且把它推入當(dāng)前執(zhí)行堆棧中。當(dāng)調(diào)用first()時(shí),js為該函數(shù)創(chuàng)建一個(gè)新的執(zhí)行上下文,并且把它推入到當(dāng)前執(zhí)行堆棧。

當(dāng)second()方法被first()調(diào)用,js引擎為該方法創(chuàng)建一個(gè)新的執(zhí)行上下文并把它推入當(dāng)前執(zhí)行堆棧。當(dāng)second()執(zhí)行完畢,這個(gè)方法的上下文就被執(zhí)行堆棧推出,并且執(zhí)行下一個(gè)執(zhí)行上下文,也就是first()。

當(dāng)first()執(zhí)行完畢,重復(fù)以上步驟。一旦執(zhí)行了所有代碼,JavaScript引擎就會(huì)從當(dāng)前堆棧中刪除全局執(zhí)行上下文。

執(zhí)行上下文如何創(chuàng)建?

直到現(xiàn)在,我們已經(jīng)知道js引擎如何管理執(zhí)行上下文的了,現(xiàn)在讓我們了解下執(zhí)行上下文如何被js創(chuàng)建的。

創(chuàng)建執(zhí)行上下文有兩個(gè)階段:1)創(chuàng)建階段,2)執(zhí)行階段(譯者:???懵逼臉)。

創(chuàng)建階段

在執(zhí)行任何JavaScript代碼之前,執(zhí)行上下文將經(jīng)歷創(chuàng)建階段。在創(chuàng)建階段會(huì)發(fā)生三件事:

this綁定

詞法環(huán)境(LexicalEnvironment)創(chuàng)建

變量環(huán)境(VariableEnvironment)創(chuàng)建

(譯者:VariableEnvironment和LexicalEnvironment譯者也是第一次聽(tīng)到,慚愧,大學(xué)沒(méi)學(xué)過(guò)編譯原理,在js中還有個(gè)this綁定,似乎是js特有)

因此,執(zhí)行上下文在概念上可以這樣表示,如下:

ExecutionContext = {
  ThisBinding = ,
  LexicalEnvironment = { ... },
  VariableEnvironment = { ... },
}
this綁定

在全局執(zhí)行上下文中,this值指向全局對(duì)象(在瀏覽器內(nèi)是window對(duì)象)。

在函數(shù)執(zhí)行上下文中,this的值取決于函數(shù)的調(diào)用的時(shí)候的情況。如果它由對(duì)象引用調(diào)用,this值就是該對(duì)象,否則this值指向全局或者為undefined(在嚴(yán)格模式下)。

例如:

let person = {
  name: "peter",
  birthYear: 1994,
  calcAge: function() {
    console.log(2018 - this.birthYear);
  }
}
person.calcAge(); 
// "this" refers to "person", because "calcAge" was called with //"person" object reference
let calculateAge = person.calcAge;
calculateAge();
// "this" refers to the global window object, because no object reference was given
詞法環(huán)境

官方es6文檔對(duì)詞法環(huán)境有如下解釋?zhuān)?/p>

詞匯環(huán)境是一種規(guī)范類(lèi)型,用于根據(jù)ECMAScript代碼的詞法嵌套結(jié)構(gòu)定義標(biāo)識(shí)符與特定變量和函數(shù)的關(guān)聯(lián)。詞匯環(huán)境由environment record(譯者:實(shí)在不知道咋翻)和外部詞匯環(huán)境的可能為null的引用組成。

(譯者:硬翻的,有點(diǎn)怪)

簡(jiǎn)而言之,詞匯環(huán)境是一種包含標(biāo)識(shí)符變量映射的結(jié)構(gòu)(此處標(biāo)識(shí)符指的是變量/函數(shù)的名稱(chēng),變量是對(duì)實(shí)際對(duì)象【包括函數(shù)類(lèi)型的對(duì)象】或原始值的引用)。

現(xiàn)在,詞法環(huán)境由兩部分組成:

(1)environment record

(2)外部環(huán)境的引用

1、environment record是存放變量和函數(shù)聲明的一個(gè)地方

2、對(duì)外部環(huán)境的引用意味著它可以訪(fǎng)問(wèn)其外部詞匯環(huán)境。

有兩種類(lèi)型的詞法環(huán)境:

一種是全局環(huán)境(在全局執(zhí)行上下文里),它沒(méi)有外部環(huán)境的引用。它的外部環(huán)境引用為null。它有全局對(duì)象(window對(duì)象)和關(guān)聯(lián)的方法和屬性(例如數(shù)組方法),以及任何用戶(hù)定義的全局變量,并且this的值指向全局對(duì)象。

一種是函數(shù)環(huán)境,它存放用戶(hù)在函數(shù)里定義的變量。并且外部環(huán)境可以指向全局環(huán)境,或者是外層函數(shù)環(huán)境。

筆記——對(duì)于函數(shù)環(huán)境,environment record還包含一個(gè)arguments對(duì)象,該對(duì)象包含索引和傳遞給函數(shù)的參數(shù)之間的映射以及傳遞給函數(shù)的參數(shù)的長(zhǎng)度(數(shù)量)。例如,下面函數(shù)的參數(shù)對(duì)象如下所示:

function foo(a, b) {
  var c = a + b;
}
foo(2, 3);
// argument object
Arguments: {0: 2, 1: 3, length: 2},

environment record也有兩種類(lèi)型:

聲明性environment record存儲(chǔ)變量,函數(shù)和參數(shù)。 一個(gè)函數(shù)環(huán)境包含聲明性environment record。

對(duì)象environment record用于定義在全局執(zhí)行上下文中出現(xiàn)的變量和函數(shù)的關(guān)聯(lián)。全局環(huán)境包含對(duì)象environment record。

抽象地說(shuō),詞法環(huán)境在偽代碼中看起來(lái)像這樣:

GlobalExectionContext = {
  LexicalEnvironment: {
    EnvironmentRecord: {
      Type: "Object",
      // Identifier bindings go here
    }
    outer: 
  }
}
FunctionExectionContext = {
  LexicalEnvironment: {
    EnvironmentRecord: {
      Type: "Declarative",
      // Identifier bindings go here
    }
    outer: 
  }
}
變量環(huán)境

它也是一個(gè)詞法環(huán)境,其EnvironmentRecord包含由此執(zhí)行上下文中的VariableStatements創(chuàng)建的綁定。

如上所述,變量環(huán)境也是一個(gè)詞匯環(huán)境,因此它具有上面定義的詞法環(huán)境的所有屬性。

在es6,詞法環(huán)境和變量環(huán)境的不同在于前者用于存儲(chǔ)函數(shù)聲明和變量(let和const)綁定,而后者用于存儲(chǔ)變量(var)的綁定。

來(lái)看個(gè)例子:

let a = 20;
const b = 30;
var c;
function multiply(e, f) {
 var g = 20;
 return e * f * g;
}
c = multiply(20, 30);

然后執(zhí)行上下文會(huì)像這樣:

GlobalExectionContext = {
  ThisBinding: ,
  LexicalEnvironment: {
    EnvironmentRecord: {
      Type: "Object",
      // Identifier bindings go here
      a: < uninitialized >,
      b: < uninitialized >,
      multiply: < func >
    }
    outer: 
  },
  VariableEnvironment: {
    EnvironmentRecord: {
      Type: "Object",
      // Identifier bindings go here
      c: undefined,
    }
    outer: 
  }
}
FunctionExectionContext = {
 
  ThisBinding: ,
  LexicalEnvironment: {
    EnvironmentRecord: {
      Type: "Declarative",
      // Identifier bindings go here
      Arguments: {0: 20, 1: 30, length: 2},
    },
    outer: 
  },
VariableEnvironment: {
    EnvironmentRecord: {
      Type: "Declarative",
      // Identifier bindings go here
      g: undefined
    },
    outer: 
  }
}

筆記——函數(shù)multiply調(diào)用時(shí)才會(huì)創(chuàng)建函數(shù)執(zhí)行上下文。

正如你所注意到的一樣,let和const定義的變量沒(méi)有綁定任何值,但var定義的變量為undefined

這是因?yàn)樵趧?chuàng)建階段,掃描代碼尋找變量和函數(shù)聲明時(shí),函數(shù)聲明完全存儲(chǔ)在環(huán)境中,但變量最初設(shè)置為undefined(var)或保持為為初始化(let、const)。

(譯者:就是var會(huì)聲明提升,而let和const不會(huì))

這就是為什么你可以在變量聲明前訪(fǎng)問(wèn)到var定義的變量,而訪(fǎng)問(wèn)let和const定義的變量則會(huì)拋出引用錯(cuò)誤。

這就是js的變量提升。

執(zhí)行階段

這是整篇文章中最簡(jiǎn)單的部分。 在此階段,完成對(duì)所有這些變量的分配,最后執(zhí)行代碼。

筆記——在執(zhí)行階段,如果js引擎在源代碼聲明的實(shí)際位置找不到let變量的值,那么它將為其分配undefined值。

結(jié)論

現(xiàn)在,我們已經(jīng)了js的部分執(zhí)行原理,雖然理解了這些概念不一定能讓你成為出色的js開(kāi)發(fā)者,但是明白了上述的概念能讓你更好理解js的其它概念,例如變量提升、閉包。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/98959.html

相關(guān)文章

  • JavaScript中的執(zhí)行下文堆棧是什么?

    摘要:每次調(diào)用函數(shù)時(shí),都會(huì)創(chuàng)建一個(gè)新的執(zhí)行上下文。理解執(zhí)行上下文和堆??梢宰屇私獯a為什么要計(jì)算您最初沒(méi)有預(yù)料到的不同值的原因。 首發(fā):https://www.love85g.com/?p=1723 在這篇文章中,我將深入研究JavaScript最基本的部分之一,即執(zhí)行上下文。在這篇文章的最后,您應(yīng)該更清楚地了解解釋器要做什么,為什么在聲明一些函數(shù)/變量之前可以使用它們,以及它們的值是如何...

    miguel.jiang 評(píng)論0 收藏0
  • JavaScript 工作原理之一-引擎,運(yùn)行時(shí),調(diào)用堆棧()

    摘要:本章會(huì)對(duì)語(yǔ)言引擎,運(yùn)行時(shí),調(diào)用棧做一個(gè)概述。調(diào)用棧只是一個(gè)單線(xiàn)程的編程語(yǔ)言,這意味著它只有一個(gè)調(diào)用棧。查看如下代碼當(dāng)引擎開(kāi)始執(zhí)行這段代碼的時(shí)候,調(diào)用棧會(huì)被清空。之后,產(chǎn)生如下步驟調(diào)用棧中的每個(gè)入口被稱(chēng)為堆棧結(jié)構(gòu)。 原文請(qǐng)查閱這里,本文采用知識(shí)共享署名 4.0 國(guó)際許可協(xié)議共享,BY Troland。 本系列持續(xù)更新中,Github 地址請(qǐng)查閱這里。 這是 JavaScript 工作原...

    Betta 評(píng)論0 收藏0
  • JavaScript 工作原理之一-引擎,運(yùn)行時(shí),調(diào)用堆棧()

    摘要:本章會(huì)對(duì)語(yǔ)言引擎,運(yùn)行時(shí),調(diào)用棧做一個(gè)概述。調(diào)用棧只是一個(gè)單線(xiàn)程的編程語(yǔ)言,這意味著它只有一個(gè)調(diào)用棧。查看如下代碼當(dāng)引擎開(kāi)始執(zhí)行這段代碼的時(shí)候,調(diào)用棧會(huì)被清空。之后,產(chǎn)生如下步驟調(diào)用棧中的每個(gè)入口被稱(chēng)為堆棧結(jié)構(gòu)。 原文請(qǐng)查閱這里,本文采用知識(shí)共享署名 4.0 國(guó)際許可協(xié)議共享,BY Troland。 本系列持續(xù)更新中,Github 地址請(qǐng)查閱這里。 這是 JavaScript 工作原...

    Alex 評(píng)論0 收藏0
  • JavaScript 如何工作:對(duì)引擎、運(yùn)行時(shí)、調(diào)用堆棧的概述

    摘要:調(diào)用棧是一種數(shù)據(jù)結(jié)構(gòu),它記錄了我們?cè)诔绦蛑械奈恢?。?dāng)從這個(gè)函數(shù)返回的時(shí)候,就會(huì)將這個(gè)函數(shù)從棧頂彈出,這就是調(diào)用棧做的事情。而且這不是唯一的問(wèn)題,一旦你的瀏覽器開(kāi)始處理調(diào)用棧中的眾多任務(wù),它可能會(huì)停止響應(yīng)相當(dāng)長(zhǎng)一段時(shí)間。 原文地址: https://blog.sessionstack.com... PS: 好久沒(méi)寫(xiě)東西了,最近一直在準(zhǔn)備寫(xiě)一個(gè)自己的博客,最后一些技術(shù)方向已經(jīng)敲定了,又可以...

    Warren 評(píng)論0 收藏0
  • JavaScript 核心(第二版)

    摘要:技術(shù)上來(lái)說(shuō)這個(gè)機(jī)制被稱(chēng)為動(dòng)態(tài)分配或代理。定義類(lèi)一個(gè)類(lèi)是一個(gè)正式的抽象集,它規(guī)定了對(duì)象的初始狀態(tài)和行為。技術(shù)上來(lái)說(shuō)一個(gè)類(lèi)表示構(gòu)造函數(shù)原型的組合。因此構(gòu)造函數(shù)創(chuàng)建對(duì)象并自動(dòng)設(shè)置新創(chuàng)建實(shí)例的原型。第二次調(diào)用時(shí),相同的上下文再次被壓入棧并恢復(fù)。 原文:JavaScript. The Core: 2nd Edition作者:Dmitry Soshnikov 文章其他語(yǔ)言版本:俄語(yǔ) 這篇文章是 ...

    dingding199389 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

qujian

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<