JavaScript之變量對象

概述

JavaScript 的可執行代碼,具備執行上下文,而每一個上下文包括如下 3 個屬性:javascript

  1. 變量對象(variable object, 簡稱 VO)
  2. 做用域鏈(scope chain)
  3. this

變量對象提供了當前環境所需的變量和函數
做用域鏈用於保證 JS 中變量和函數有序地訪問
this 爲函數提供了執行者對象java

一個上下文的執行週期能夠用下圖示意:
express

本文就來介紹執行上下文中的變量對象數組

那什麼是變量對象呢?先看定義:瀏覽器

變量對象是與執行上下文相關的數據做用域,用於存儲執行上下文中的變量和函數聲明。bash

不一樣的執行上下文,變量對象會有一些差異。接下來就分別針對不一樣的上下文討論其區別。閉包

1、全局上下文

全局對象(Global object) 是在進入任何執行上下文以前就已經建立了的對象; 這個對象只存在一份,它的屬性在程序中任何地方均可以訪問,全局對象的生命週期終止於程序退出那一刻。app

在全局代碼的上下文執行環境中,變量對象就是全局對象,在瀏覽器中,就是 window 對象。函數

此時,咱們能夠用 this 和 self 來訪問到全局對象,也就是它自己post

console.log(this)  // window
console.log(self)  // window
複製代碼

其次,全局對象初始建立階段將 Math、String、Date、parseInt 等函數做爲自身方法,還會把全局變量做爲本身的屬性。

用僞代碼表示就是:

global = {
    Math: <...> Date: <...> window: global // 引用自身 } 複製代碼

2、函數上下文

咱們已經知道,變量對象存儲量執行上下文中的函數聲明和變量,在函數上下文中,多了arguments(函數參數列表), 一個類數組對象。

用僞代碼來表示:

VO = {
    arguments: Arguments,
    variables: undefine,
    functionName: <Function reference>
}
複製代碼

函數未進入執行階段以前,變量對象中的屬性都不能訪問!可是進入執行階段以後,變量對象轉變爲了活動對象(activation object)。

因此,在函數上下文中,咱們將活動對象(activation object)做爲變量對象,活動對象最開始只包含一個變量就是 arguments 對象(這個對象是全局環境中沒有的)。

arguments 的屬性值 Arguments 它包括以下屬性:

  • callee — 誰調用了本函數
  • length — 真正傳遞的參數個數
  • properties-indexes (字符串類型的整數) 屬性的值就是函數的參數值(按參數列表從左到右排列)

3、建立過程

咱們再一次來看這個過程圖:

建立階段

全局對象初始化的時候,就將變量對象引用了自身。 而函數的建立卻有須要注意的地方。

函數在建立階段就建立了變量對象
其中,變量對象包括:

  1. 當前函數的參數列表,創建 Arguments 對象。
  2. 全部的函數聲明(不包括函數表達式哦!),直接指向函數
  3. 全部的變量聲明(var 聲明的變量),默認爲 undefined

進入執行上下文時,函數聲明和變量聲明都會提早,這就是聲明提高,可是變量聲明的值都是undefined,而函數聲明的變量已經能夠指向函數。變量聲明的優先級最低。

看下面這段代碼:

function foo(a, b) {
  var c = 10;
  function d() {}
  var e = function _e() {};
  (function x() {});
}
  
foo(10); 
複製代碼

當進入函數 foo 時,其變量對象的表現形式爲:

VO = {
    arguments: {
        0: 10,
        1: undefined,
        length: 1
    }
    c: undefined,
    d: <function reference to d>, e: undefined, } 複製代碼

x 是函數表達式,因此不在變量對象當中,e 變量引用的值也是函數表達式,因此變量 e 自己是聲明,因此在變量對象當中。

執行階段

當前進入執行階段,變量對象激活成活動對象,函數會順序執行代碼,改變變量對象的值:
以上代碼就變成:

AO = {
    arguments: {
        0: 10,
        1: undefined,
        length: 1
    }
    c: 10,
    d: <reference to function declaration d>,
    e: <reference to Function expression to _e>,
}
複製代碼

接下來看一段代碼:

console.log(foo);

function foo() {
    console.log("123")
}

var foo = "456";
複製代碼

以上會打印函數,是由於:

變量優先處理函數聲明,再是變量聲明。

再看一段代碼:

if (true) {
  var a = 1;
} else {
  var b = 2;
}
console.log(a);  // 1
console.log(b);  // undefined
複製代碼

雖然 else 中的代碼永遠不會被執行,可是 b 的變量聲明在執行以前就默認被設置成 undefined了。

總結

執行上下文包括三個屬性,變量對象,做用域鏈,this, 不一樣的執行上下文,變量對象是有區別的。

全局上下文中,變量對象就是自己。

函數上下文中,變量對象包括:arguments, 函數聲明,變量聲明。在函數建立階段,變量對象有默認值,進入執行階段後,變量對象會被激活成活動對象,而後變量對象的值被順序改變。

歡迎關注個人我的公衆號「謝南波」,專一分享原創文章。

掘金專欄 JavaScript 系列文章

  1. JavaScript之變量及做用域
  2. JavaScript之聲明提高
  3. JavaScript之執行上下文
  4. JavaScript之變量對象
  5. JavaScript原型與原型鏈
  6. JavaScript之做用域鏈
  7. JavaScript之閉包
  8. JavaScript之this
  9. JavaScript之arguments
  10. JavaScript之按值傳遞
  11. JavaScript之例題中完全理解this
  12. JavaScript專題之模擬實現call和apply
相關文章
相關標籤/搜索