ECMA-262-3詳解(2)變量對象

原文地址程序員

做者的話

有不少文章已經對ECMAScript的核心概念作了詳盡解讀。本系列文章翻譯自Dmitry Soshnikov的我的網站,相信很多人已經看過原文或者譯文。原文簡潔易懂而且嚴謹,條理清晰地闡明瞭全部JavaScript開發者不得不深刻理解的ECMAScript核心概念。重複翻譯的緣由主要是爲了我的收藏、整理之用。初次翻譯,技巧拙劣,若有不足,請不吝賜教。ecmascript

正文

  1. 介紹
  2. 數據聲明
  3. 不一樣執行上下文中的變量對象函數

    1. 全局上下文中的變量對象
    2. 函數上下文中的變量對象
  4. 處理上下文代碼的階段oop

    1. 進入執行上下文
    2. 代碼執行
  5. 關於變量
  6. 實現的特色:__parent__屬性
  7. 結論

介紹

咱們老是在程序中聲明函數和變量,而後成功地用做構建咱們的系統。可是,解釋器怎樣以及在哪裏找到咱們的數據(函數和變量)?當咱們引用須要的對象的時候發生了什麼?網站

許多ECMAScript開發者知道變量和執行上下文緊密相關。this

var a = 10; // variable of the global context
 
(function () {
  var b = 20; // local variable of the function context
})();
  
alert(a); // 10
alert(b); // "b" is not defined

同時,許多程序員也知道當前版本(ES6以前,譯者注)的標準的獨立做用域是經過「函數」代碼類型的執行上下文建立的。好比,和C/C++相反,ECMAScript中的for循環塊不會建立本地上下文。翻譯

for (var k in {a: 1, b: 2}) {
  alert(k);
}
  
alert(k); // variable "k" still in scope even the loop is finished

讓咱們看看當咱們聲明數據時的所發生的細節。code

數據聲明

若是變量和執行上下文相關,那麼應該知道變量的數據存在哪裏以及如何獲取它們。這個機制被稱爲變量對象orm

變量對象(簡稱:VO)是一個與執行上下文相關的特殊對象,它存儲了在上下文中聲明的:對象

  • 變量
  • 函數聲明
  • 函數形參

注意,在ES5中,變量對象的概念已經被詞法環境模式取代,能夠在適當的章節找到它的詳細描述。

示意性的舉個例子,能夠將變量對象表示成一個普通的ECMAScript對象:

VO = {};

正如咱們所說,VO是執行上下文的屬性:

activeExecutionContext = {
  VO: {
    // context data (var, FD, function arguments)
  }
};

只容許在全局上下文(全局對象就是變量對象的地方)中,對變量間接引用(經過VO的屬性名)。對於其餘上下文,對VO對象的直接引用是不可能的,這純粹是實現機制。

當咱們聲明瞭一個變量或函數,除了使用咱們的變量的名字和值建立VO的新屬性,沒別的了。
好比:

var a = 10;
 
function test(x) {
  var b = 20;
};
 
test(30);

相應的變量對象是這樣:

// Variable object of the global context
VO(globalContext) = {
  a: 10,
  test: <reference to function>
};
  
// Variable object of the "test" function context
VO(test functionContext) = {
  x: 30,
  b: 20
};

可是在實現層面(以及規範)中,變量對象是一個抽象的概念。物理上,在具體的執行上下文中,VO被叫作不一樣的名稱,有不一樣的初始結構。

不一樣執行上下文中的變量對象

對於全部的執行上下文類型,變量對象的一些操做(好比變量實例化)和行爲是共通的。從這點看,將變量對象看做是抽象的基礎的東西很便利。函數上下文也能夠定義與變量對象相關的額外內容。

AbstractVO (generic behavior of the variable instantiation process)
 
  ║
  ╠══> GlobalContextVO
  ║        (VO === this === global)
  ║
  ╚══> FunctionContextVO
           (VO === AO, <arguments> object and <formal parameters> are added)

咱們詳細解讀一下。

全局上下文的變量對象

如今,應該先給出全局對象的定義。

全局對象是在進入任何執行上下文前建立的對象;這個對象僅存在一份,它的屬性能夠在程序的任何位置訪問到, 全局對象的生命週期伴隨着程序結束而結束。

在建立時,全局對象使用諸如:Math、String、Date、parseInt等初始化,也可使用附加對象初始化,附加對象能夠是全局對象自己的引用--好比在BOM中,全局對象的window屬性引用全局對象(不是在全部的實現中都是如此)。

global = {
  Math: <...>,
  String: <...>
  ...
  ...
  window: global
};

當引用全局對象的屬性,前綴每每能夠省略,由於全局對象不能經過名字直接訪問到。然而,在全局上下文中能夠經過this值訪問到它,也能夠經過對它的遞歸引用訪問到它,好比BOM中的window,所以能夠簡寫:

String(10); // means global.String(10);
 
// with prefixes
window.a = 10; // === global.window.a = 10 === global.a = 10;
this.b = 20; // global.b = 20;

因此回到全局上下文的變量對象,這裏變量對象就是全局對象自己:

VO(globalContext) === global;

頗有必要理解這個事實,因爲這個緣由,在全局上下文中聲明一個變量,咱們能夠經過全局對象的屬性間接訪問它(好比,當變量名事先未知時):

var a = new String('test');
 
alert(a); // directly, is found in VO(globalContext): "test"
 
alert(window['a']); // indirectly via global === VO(globalContext): "test"
alert(a === this.a); // true
  
var aKey = 'a';
alert(window[aKey]); // indirectly, with dynamic property name: "test"

函數上下文的變量對象

相關文章
相關標籤/搜索