原文地址程序員
有不少文章已經對ECMAScript的核心概念作了詳盡解讀。本系列文章翻譯自Dmitry Soshnikov的我的網站,相信很多人已經看過原文或者譯文。原文簡潔易懂而且嚴謹,條理清晰地闡明瞭全部JavaScript開發者不得不深刻理解的ECMAScript核心概念。重複翻譯的緣由主要是爲了我的收藏、整理之用。初次翻譯,技巧拙劣,若有不足,請不吝賜教。ecmascript
咱們老是在程序中聲明函數和變量,而後成功地用做構建咱們的系統。可是,解釋器怎樣以及在哪裏找到咱們的數據(函數和變量)?當咱們引用須要的對象的時候發生了什麼?網站
許多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"