我對「詞法環境」「執行上下文」的理解

2021-09-30 13:19:07 字數 2751 閱讀 5879

execution context,lexical environment左邊的這兩個單字出自ecma標準用於規範語言實現,也就是回答「**是怎樣被執行的?」。我沒有耐心仔細的研讀規範,如果日後我有了耐心研讀了規範,並且寫了更多的**,看了更多的書,我的認識可能會改變。但是現在我還是想闡述一下我對這兩個單詞的認識。以下內容在寫作時沒有外部參考文獻,但是內容受到很多文章的啟發,更確切的來說有很多是其他人的觀點。

回答「**是怎樣被執行」這個問題,肯定不可以很深入,現在是研究前端就停留在前端的深度上就好了,如果走到了組合語言,扯到了「取指執行」這種層次就太沒有必要了,我也不會。回到這個問題上來。以下我用一段話,基於我的個人認知,回答這個問題。

var a = "global a"; 

function haoming()

with() )();

(function a () )();

(function() )();

function func()

return func1;

}}var func1 = func();

func1();

haoming();

首先,直譯器「預處理」全域性作用域的**,將變數宣告,函式定義,

新增到乙個lexical environme物件上,設定this值為全域性物件(在瀏覽器環境為window),還有設定變數物件(我暫且認為變數物件和詞法環境物件相同,但是它們肯定不同,要不然標準為什麼要設計它呢,所以後文我忽略它,它的功能都假裝由詞法環境物件實現,在初始化時,它們肯定是一樣的)。注意哦,在這個階段,

變數的值是沒有初始化的,函式宣告會初始化乙個函式物件,在這個函式物件中有乙個「作用域」屬性,這個屬性的值很有用。但是函式表示式在這個階段是不會被處理的,它只會像變數宣告一樣,是乙個沒有初始化的變數。這一點其實已經可以解釋很多問題了,比如變數宣告提前,函式宣告提前(可以在函式宣告**前使用函式)。然後這三個物件組成乙個執行上下文物件新增到執行棧的頂部,直到整個程式執行完畢,這個全域性執行上下物件才會離開執行棧。然後,直譯器開始按照**書寫順序執行**,解釋一些語句。直到,它遇到了with語句(一般情況下沒有人會用with語句,會影響效能,而且**變得很奇怪),這個時候,我猜測,會建立乙個新的執行上下文物件,新增到棧頂,它的詞法環境就是括號中的物件。然後繼續執行**,遇到乙個使用了『a』變數的語句,從棧頂的詞法環境開始查詢,確定值是「with a」,遇到乙個使用this的語句,this的確定規則我們後文再講,此時直接讀取棧頂的this值是window。繼續執行遇到乙個『立刻執行的函式表示式』,首先創造乙個新的執行上下文物件,它的詞法環境中有乙個匿名函式物件,然後再創造乙個函式上下文物件,根據函式物件的「作用域」屬性,處理堆疊,如果作用域屬性形成的鏈和從棧頂到棧底的執行上下文物件(中的詞法環境)鏈一樣,那麼棧不改變,否則棧改變為」作用域鏈「的順序。然後預處理函式執行上下文物件中的變數宣告,函式宣告,之後按照函式內部**的順序執行函式**,輸出this.a,直接讀取this值,this為window,從棧頂開始到底部查詢window的值,讀取它的a屬性。輸出a的值,從棧頂到棧底查詢它的值,在with執行上下文中確定它的值為」with a 」,執行完了當前函式的所有**,彈出該函式執行上下物件,彈出只有乙個匿名函式物件的執行上下文物件。繼續執行遇到乙個」命名的立刻執行函式表示式「,和上文一樣創造插入乙個(詞法環境)只有乙個命名函式物件的執行上下文物件(這個唯一值不可以修改),利用該函式物件創造和插入乙個函式執行上下文物件,訪問this.a,確定this值為window,向下查詢window,輸出它的a屬性值,訪問a變數,向下查詢a變數。在with執行上下問中找到,輸出」with a「彈出當前的函式執行上下文物件,和只有乙個值的執行上下文物件。結束with內部的**執行,彈出with執行上下文物件,此時,執行棧中又只有全域性執行上下文物件了,執行func函式,根據函式物件的作用域鏈屬性更改執行棧(好像只有閉包要更改),根據上文講訴直接建立乙個函式執行上下文壓入棧中(注意,沒有那個只有乙個值的執行上下文)。開始執行函式中的**,查詢a變數,在全域性執行上下文中獲取到。結束該函式的執行,彈出棧頂項。執行func1,根據函式物件的作用域鏈屬性更新棧(這是唯一要更新的地方,因為func1的作用域鏈屬性棧頂多了乙個閉包),向棧中壓入乙個閉包的執行上下文,建立函式的執行上下文壓入棧中,查詢b變數,從棧頂往下查詢,在閉包中查詢到值。結束函式執行。彈出函式執行上下文物件。彈出和它關聯的閉包執行上下文。流程基本結束。彈出全域性執行上下文,執行棧清空。

上文中扯了一大堆,超級希望你理解了我的意思。我在上一段中有很多次把執行上下文,和詞法環境混淆,其實執行上下文中最重要的就是詞法環境了,this值不怎麼重要,變數物件和詞法環境基本沒差別。理解了上一段,關於js的作用域問題再也不是問題了。我還看過有人用樹的方法來理解作用域(把每個詞法環境當作乙個樹節點),其實也是不錯的方法。沒準某個實現還真的混了樹和棧來做。

現在已經不需要我回答詞法環境和執行上下文是什麼了。詞法環境在標準中還是有點複雜的,由環境記錄和outter屬性組成,outter屬性就是我前面說到的函式物件中的作用域鏈屬性,它們的值是一樣的。當創造函式物件時會把棧頂的outter賦值給它創造的那個函式物件的作用域鏈屬性。所以說,在大部分情況,是不會發生作用域鏈和棧不同而更新棧的情況。環境記錄可以是物件或者宣告集合,是物件的情況比如with語句,全域性的執行上下文中的詞法環境,直接就是括號中的物件和window物件,這種的特定是可以更改詞法環境中的項。(預處理以後還可以更改)另一種就是函式的詞法環境物件並不是乙個我們可以控制的物件,雖然如此說,它的內部應該也實現為乙個物件。執行上下文包裹了詞法環境。

this值如何確定?

如果乙個函式是作為物件的方法被呼叫的那麼,this值就是這個物件。否則this值就是window。如何識別乙個函式是否是作為物件的方法被呼叫的呢?

js執行上下文 this指向的理解

this 是很多人會混淆的概念,但是其實它一點都不難,只是網上很多文章把簡單的東西說複雜了。在這一小節中,你一定會徹底明白 this 這個概念的。this的指向在函式定義的時候是確定不了的,只有函式執行的時候才能確定this到底指向誰,實際上this的最終指向的是那個呼叫它的物件 這句話有些問題,後...

程序上下文與中斷上下文的理解

一.什麼是核心態和使用者態 使用者態 使用者程式執行空間。1.程序上下文 1 程序上文 其是指程序由使用者態切換到核心態是需要儲存使用者態時cpu暫存器中的值,程序狀態以及堆疊上的內容,即儲存當前程序的程序上下文,以便再次執行該程序時,能夠恢復切換時的狀態,繼續執行。2 程序下文 其是指切換到核心態...

程序上下文與中斷上下文的理解

使用者態 使用者程式執行空間。1.程序上下文 1 程序上文 其是指程序由使用者態切換到核心態是需要儲存使用者態時cpu暫存器中的值,程序狀態以及堆疊上的內容,即儲存當前程序的程序上下文,以便再次執行該程序時,能夠恢復切換時的狀態,繼續執行。2 程序下文 其是指切換到核心態後執行的程式,即程序執行在核...