天天看點

[JavaScript]ECMA-262-3 深入解析.第一章.執行上下文

<a href="http://www.cnblogs.com/justinw/archive/2010/04/16/1713086.html#additional-literature">其他參考</a>

這篇文章我們主要探讨ECMAScript執行上下文和相關的ECMAScript可執行代碼。

每次當控制器轉到ECMAScript可執行代碼的時候,即會進入到一個執行上下文。

執行上下文(簡稱-EC)是一個抽象概念,ECMA-262标準用這個概念同可執行代碼(executable code)概念進行區分。

标準規範沒有從技術實作的角度準确定義EC的類型和結構;這應該是具體實作ECMAScript引擎時要考慮的問題。

活動的執行上下文在邏輯上組成一個堆棧。堆棧底部永遠都是全局上下文(global context),堆棧頂部是目前(活動的)執行上下文。堆棧在EC類型的變量(various kingds of EC)被推入或彈出的同時被修改。

可執行代碼的概念與抽象的執行上下文的概念是相對的。在某些時刻,可執行代碼與執行上下文是等價的。

例如,我們可以定義一個數組來模拟執行上下文堆棧:

1

<code>ECStack = [];</code>

每次進入函數 (即使函數被遞歸調用或作為構造函數) 的時候或者内置的eval函數工作的時候,這個堆棧都會被推入。

這種類型的代碼是在"程式"級處理的:例如加載外部的js檔案或者本地的在&lt;script&gt;&lt;/script&gt;标簽内的代碼。全局代碼不包括任何函數體内的代碼。

在初始化(程式啟動)階段,ECStack是這樣的:

2

3

<code>ECStack = [</code>

<code>  </code><code>globalContext</code>

<code>];</code>

當進入函數代碼(所有類型的函數),ECStack被推入新元素。要注意的是,具體的函數代碼不包括内部函數(inner functions)代碼。如下所示,我們使函數自己調自己的方式遞歸一次:

4

5

6

<code>(</code><code>function</code>  <code>foo(bar) {</code>

<code>  </code><code>if</code> <code>(bar) {</code>

<code>    </code><code>return</code><code>;</code>

<code>  </code><code>}</code>

<code>  </code><code>foo(</code><code>true</code><code>);</code>

<code>})();</code>

那麼,ECStack以如下方式被改變:

7

8

9

10

11

12

<code>// first activation of foo</code>

<code>  </code><code>&lt;foo&gt; functionContext</code>

<code> </code> 

<code>// recursive activation of foo</code>

<code>  </code><code>&lt;foo&gt; functionContext – recursively</code>

每次傳回存在的目前執行上下文和ECStack彈出相應的執行上下文的時候,棧指針會自動移動位置,這是一個典型的堆棧實作方式。一個被抛出但是沒有被截獲的異常,同樣存在一個或多個執行上下文。當相關段代碼執行完以後,直到整個應用程式結束,ECStack都隻包括全局上下文(global context)。

 eval 代碼有點兒意思。它有一個概念: 調用上下文(calling context), 這是一個當eval函數被調用的時候産生的上下文。eval(變量或函數聲明)活動會影響調用上下文(calling context)。

<code>eval(</code><code>'var x = 10'</code><code>);</code>

<code>(</code><code>function</code> <code>foo() {</code>

<code>  </code><code>eval(</code><code>'var y = 20'</code><code>);</code>

<code>alert(x);</code><code>// 10</code>

<code>alert(y);</code><code>// "y" is not defined</code>

ECStack的變化過程:

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

<code>// eval('var x = 10');</code>

<code>ECStack.push(</code>

<code>  </code><code>evalContext,</code>

<code>  </code><code>callingContext: globalContext</code>

<code>);</code>

<code>// eval exited context</code>

<code>ECStack.pop();</code>

<code>// foo funciton call</code>

<code>ECStack.push(&lt;foo&gt; functionContext);</code>

<code>// eval('var y = 20');</code>

<code>  </code><code>callingContext: &lt;foo&gt; functionContext</code>

<code>// return from eval</code>

<code>// return from foo</code>

看到了吧,這是一個非常普通的邏輯調用堆棧

在版本号1.7以上的SpiderMonkey(内置于Firefox,Thunderbird)的實作中,可以把調用上下文作為第二個參數傳遞給eval。那麼,如果這個上下文存在,就有可能影響“私有”(類似以private關鍵字命名的變量一樣)變量。

<code>function</code> <code>foo() {</code>

<code>  </code><code>var</code> <code>x = 1;</code>

<code>  </code><code>return</code> <code>function</code> <code>() { alert(x); };</code>

<code>};</code>

<code>var</code> <code>bar = foo();</code>

<code>bar();</code><code>// 1</code>

<code>eval(</code><code>'x = 2'</code><code>, bar);</code><code>// pass context, influence on internal var "x"</code>

<code>bar();</code><code>// 2</code>

這篇文章的内容是未來分析其他跟執行上下文相關的主題(例如變量對象,作用域鍊,等等)的最起碼的理論基礎,這些主題将在後續章節中講到。

本文轉自Justin部落格園部落格,原文連結:http://www.cnblogs.com/justinw/archive/2010/04/16/1713086.html,如需轉載請自行聯系原作者

繼續閱讀