首頁 web前端 js教程 js中對執行上下文以及變數物件的解析

js中對執行上下文以及變數物件的解析

Aug 14, 2018 am 10:02 AM
javascript

這篇文章帶給大家的內容是關於js中對執行上下文以及變數物件的解析 ,有一定的參考價值,有需要的朋友可以參考一下,希望對你有所幫助。

執行上下文(Execution Context)

JavaScript程式碼執行的過程,包括編譯和執行兩個階段,編譯就是透過詞法分析,建構抽象抽象語法樹,並且編譯成機器識別的指令,在JavaScript程式碼編譯階段,作用域規則就已經確定了;在程式碼執行階段,或者函數一旦調用,便會創建執行上下文(Execution Context),也叫執行環境

在ECMA-262中有下列一段定義

當控制器轉入ECMA 腳本的可執行程式碼時,控制器會進入一個執行環境。目前活動的多個執行環境在邏輯上形成一個堆疊結構。此邏輯棧的最頂層的執行環境稱為目前運行的執行環境。任何時候,當控制器從目前執行的執行環境相關的可執行程式碼轉入與該執行環境無關的可執行程式碼時,會建立一個新的執行環境。新建的這個執行環境會被推入堆疊中,成為目前運行的執行環境.

這也是一個抽象的概念,在一段JavaScript程式碼中,會建立多個執行上下文,執行上下文定義了變數或函數有權存取的其他資料, ,透過閱讀規範及相關文檔,了解到執行上下文(簡稱EC)主要包括三個點,用偽代碼表示如下:

EC = {
    this: // 绑定this指向为当前执行上下文, 如果函数属于全局函数,则this指向window
    scopeChain: [] // 创建当前执行环境的作用域链,
    VO: {} // 当前环境的变量对象(Variable Object),每个环境都有一个与之关联的变量对象
}
登入後複製

看下面這段程式碼:

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

foo()
登入後複製
  • 1.執行這段程式碼,首先會建立全域上下文globleEC,並推入執行上下文堆疊中;

  • ##2.當調用foo()時便會建立foo的上下文fooEC,並推入執行上下文堆疊中;

  • #3.當呼叫bar()時便會建立bar的上下文barEC,並推入執行上下文堆疊中;

  • 4.當bar函數執行完,barEC就會從執行上下文堆疊中彈出;

  • 5.當foo函數執行完,fooEC便會從執行上下文堆疊中彈出;

  • #6.在瀏覽器視窗關閉後,全域上下文globleEC會從執行上下文堆疊中彈出;

總結: 堆疊底部永遠都是全域上下文,而堆疊頂部就是目前正在執行的上下文,只有當瀏覽器關閉時,全域上下文才會從執行上下文堆疊中彈出

變數物件(Variable Object):

每一個執行環境都有一個與之關聯的變數對象,是一個抽象的概念,環境中定義的所有變數和函數都保存在這個物件中。雖然我們寫的程式碼無法存取這個對象,但單解析器在處理資料時會在後台使用它們。
當瀏覽器第一次載入js腳本程式的時候, 預設進入全域執行環境, 這次的全域環境變數物件為window, 在程式碼中可以存取。

如果環境是函數, 則將此活動物件做為當前上下文的變數物件(VO = AO), 此時變數物件是不可透過程式碼來存取的,下面主要對活動物件進行講解。

活動物件(Activation Object)

1、初始化活動物件(下文縮寫為AO)

當函數一調用,立刻建立當前上下文的活動對象, 並將活動對像作為變數對象,透過arguments屬性初始化,值為arguments對象(傳入的實參集合,與形參無關,形參做為局部環境的局部變數被定義)

AO = {
  arguments: <ArgO>
};
登入後複製
arguments物件有以下屬性:

  • length: 真正傳遞參數的數量;

  • callee: 指向目前函數的參考,也就是被呼叫的函數;

  • #'類別index': 字串型別的整數, 值就是arguments物件中物件下標的值,arguments物件應和陣列加以區別, 它就是arguments物件,只是能和陣列具有相同的length屬性,和可以透過下標來存取值

  • #
function show (a, b, c) {
    // 通过Object.prototype.toString.call()精准判断类型, 证明arguments不同于数组类型
    var arr = [1, 2, 3];
    console.log(Object.prototype.toString.call(arr)); // [object Array]

    console.log(Object.prototype.toString.call(arguments)); // [object Arguments]

    console.log(arguments.length) // 2  传递进来实参的个数

    console.log(arguments.callee === show) // true 就是被调用的函数show自身

    //参数共享

    console.log(a === arguments[0]) // true

    a = 15;

    console.log(arguments[0]) // 15

    arguments[0] = 25;

    console.log(a)  // 25;

    但是,对于没有传进来的参数c, 和arguments的第三个索引是不共享的

    c = 25;

    console.log(arguments[2]) // undefined

    argument[2] = 35;

    console.log(c) // 25

}

show(10, 20);
登入後複製
接著往下走,這才是關鍵的地方,執行環境的程式碼被分成兩個階段來處理:

  1. #進入執行環境

  2. 執行函數的程式碼

2、進入執行環境

函數如果被呼叫, 進入執行環境(上下文),並立即建立活動物件, 透過arguments屬性初始化, 同時會掃描執行環境中的所有形參、所有函數宣告、所有變數宣告, 新增到活動物件(AO), 並確定this的值,然後會開始執行程式碼。

在進入執行環境這個階段:

所有形參宣告:

形參牌名稱作為活動物件屬性被創建, 如果傳遞實參, 值就為實參值, 如果沒有傳遞參數, 值就為undefined

#所有函數聲明:

函數名稱作為活動對象的屬性被創建,值是一個指標在記憶體中, 指向這個函數,如果變數物件已經存在相同名稱的屬性, 則完全替換。

所有變數宣告:

所有变量名称作为活动对象的属性被创建, 值为undefined,但是和函数声明不同的是, 如果变量名称跟已经存在的属性(形式参数和函数)相同、则不会覆盖
function foo(a, b) {
    var c = 10;
    function d() {
        console.log('d');
    }
    var e = function () {
        console.log('e');
    };
    (function f() {})
    if (true) {
        var g = 20;
    } else {
        var h = 30;
    }
}

foo(10);
登入後複製

此时在进入foo函数执行上下文时,foo的活动对象fooAO为:

fooAO = {
    arguments: {
        0: 10,
        length: 1
    },
    a: 10,
    b: undefined,
    c: fundefined,
    d: <d reference>  //指向d函数的指针,
    e: undefined,
    g: undefined,
    h: undefined  // 虽然else中的代码永远不会执行,但是h仍然是活动对象中的属性
}
登入後複製

这个例子做如下几点说明:

  • 1.关于函数,只会创建函数声明作为活动对象的属性, 而f函数作为函数表达式并不会出现在活动对象(AO)中

  • 2.e虽然值是一个函数, 但是作为变量属性被活动对象创建

3、代码执行阶段

在进入执行上下文阶段,活动对象拥有了属性,但是很多属性值为undefined, 到代码执行阶段就开始为这些属性赋值了

还是上面的代码例子, 此时活动对象如下:

fooAO = {
    arguments: {
        0: 10,
        length: 1
    },
    a: 10,
    b: undefined,
    c: 10, // 赋值为undefined
    d: <d reference>  //指向d函数的指针,
    e: <d reference>  // 指向e函数的指针
    g: 20,
    h: undefined  // 声明h变量,但是没有赋值
}
登入後複製

变量对象包括:{ arguments对象+函数形参+内部变量+函数声明(但不包含表达式) }

这时这个活动对象, 即作为当前执行环境的变量对象会被推到此执行环境作用域链的最前端(作用域链本篇不做介绍,会在下一篇文章中单独讲解作用域和作用域链), 假定执行环境为一个对象,则整个执行环境可以访问到的属性如下:

伪代码如下:

fooExecutionContext = {
    scopeChain: [], //fooAO +所有父执行环境的活动对象,
    fooAO: {
        arguments: {
            0: 10,
            length: 1
        },
        a: 10,
        b: undefined,
        c: 10, // 赋值为undefined
        d: <d reference>  //指向d函数的指针,
        e: <d reference>  // 指向e函数的指针
        g: 20,
        h: undefined
    },
    this: 当前执行环境的上下文指针
}
登入後複製

补充:

下面的例子为了说明一下变量声明的顺序及变量同名不会影响函数声明

console.log(foo); //  foo的函数体
var foo = 10;
console.log(foo) // 10
function foo() {};
foo = 20;
console.log(foo); // 20
登入後複製

在代码执行之前, 就会读取函数声明,变量声明的顺序在函数声明和形参声明之后, 整个流程如下:

进入执行环境阶段:

1. var VO = {}
2. VO[foo] = 'foo函数指针'
3. 扫描到var foo = 10,

 // 但是foo做为function已经声明,所以变量声明不会影响同名的函数声明,如果代码中没有foo函数声明的话,则foo为undefined
登入後複製

代码执行阶段:

1. VO[foo] = 10;
2. VO[foo] = 20;
登入後複製

解析代码完成。

相关推荐:

js对象是什么?js对象的介绍(附代码)

Js中前端模块化的详细分析及其区别对比

js中字符方法以及字符串操作方法的总结(附代码)

以上是js中對執行上下文以及變數物件的解析的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

如何使用WebSocket和JavaScript實現線上語音辨識系統 如何使用WebSocket和JavaScript實現線上語音辨識系統 Dec 17, 2023 pm 02:54 PM

如何使用WebSocket和JavaScript實現線上語音辨識系統引言:隨著科技的不斷發展,語音辨識技術已成為了人工智慧領域的重要組成部分。而基於WebSocket和JavaScript實現的線上語音辨識系統,具備了低延遲、即時性和跨平台的特點,成為了廣泛應用的解決方案。本文將介紹如何使用WebSocket和JavaScript來實現線上語音辨識系

WebSocket與JavaScript:實現即時監控系統的關鍵技術 WebSocket與JavaScript:實現即時監控系統的關鍵技術 Dec 17, 2023 pm 05:30 PM

WebSocket與JavaScript:實現即時監控系統的關鍵技術引言:隨著互聯網技術的快速發展,即時監控系統在各個領域中得到了廣泛的應用。而實現即時監控的關鍵技術之一就是WebSocket與JavaScript的結合使用。本文將介紹WebSocket與JavaScript在即時監控系統中的應用,並給出程式碼範例,詳細解釋其實作原理。一、WebSocket技

如何利用JavaScript和WebSocket實現即時線上點餐系統 如何利用JavaScript和WebSocket實現即時線上點餐系統 Dec 17, 2023 pm 12:09 PM

如何利用JavaScript和WebSocket實現即時線上點餐系統介紹:隨著網路的普及和技術的進步,越來越多的餐廳開始提供線上點餐服務。為了實現即時線上點餐系統,我們可以利用JavaScript和WebSocket技術。 WebSocket是一種基於TCP協定的全雙工通訊協議,可實現客戶端與伺服器的即時雙向通訊。在即時線上點餐系統中,當使用者選擇菜餚並下訂單

如何使用WebSocket和JavaScript實現線上預約系統 如何使用WebSocket和JavaScript實現線上預約系統 Dec 17, 2023 am 09:39 AM

如何使用WebSocket和JavaScript實現線上預約系統在當今數位化的時代,越來越多的業務和服務都需要提供線上預約功能。而實現一個高效、即時的線上預約系統是至關重要的。本文將介紹如何使用WebSocket和JavaScript來實作一個線上預約系統,並提供具體的程式碼範例。一、什麼是WebSocketWebSocket是一種在單一TCP連線上進行全雙工

JavaScript與WebSocket:打造高效率的即時天氣預報系統 JavaScript與WebSocket:打造高效率的即時天氣預報系統 Dec 17, 2023 pm 05:13 PM

JavaScript和WebSocket:打造高效的即時天氣預報系統引言:如今,天氣預報的準確性對於日常生活以及決策制定具有重要意義。隨著技術的發展,我們可以透過即時獲取天氣數據來提供更準確可靠的天氣預報。在本文中,我們將學習如何使用JavaScript和WebSocket技術,來建立一個高效的即時天氣預報系統。本文將透過具體的程式碼範例來展示實現的過程。 We

簡易JavaScript教學:取得HTTP狀態碼的方法 簡易JavaScript教學:取得HTTP狀態碼的方法 Jan 05, 2024 pm 06:08 PM

JavaScript教學:如何取得HTTP狀態碼,需要具體程式碼範例前言:在Web開發中,經常會涉及到與伺服器進行資料互動的場景。在與伺服器進行通訊時,我們經常需要取得傳回的HTTP狀態碼來判斷操作是否成功,並根據不同的狀態碼來進行對應的處理。本篇文章將教你如何使用JavaScript來取得HTTP狀態碼,並提供一些實用的程式碼範例。使用XMLHttpRequest

javascript如何使用insertBefore javascript如何使用insertBefore Nov 24, 2023 am 11:56 AM

用法:在JavaScript中,insertBefore()方法用於在DOM樹中插入一個新的節點。這個方法需要兩個參數:要插入的新節點和參考節點(即新節點將要插入的位置的節點)。

JavaScript與WebSocket:打造高效率的即時影像處理系統 JavaScript與WebSocket:打造高效率的即時影像處理系統 Dec 17, 2023 am 08:41 AM

JavaScript是一種廣泛應用於Web開發的程式語言,而WebSocket則是一種用於即時通訊的網路協定。結合二者的強大功能,我們可以打造一個高效率的即時影像處理系統。本文將介紹如何利用JavaScript和WebSocket來實作這個系統,並提供具體的程式碼範例。首先,我們需要明確指出即時影像處理系統的需求和目標。假設我們有一個攝影機設備,可以擷取即時的影像數

See all articles