<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檔案或者本地的在<script></script>标簽内的代碼。全局代碼不包括任何函數體内的代碼。
在初始化(程式啟動)階段,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><foo> functionContext</code>
<code> </code>
<code>// recursive activation of foo</code>
<code> </code><code><foo> 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(<foo> functionContext);</code>
<code>// eval('var y = 20');</code>
<code> </code><code>callingContext: <foo> 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,如需轉載請自行聯系原作者