深入理解JavaScript系列(11) 執(zhí)行上下文(Execution Contexts)
更新時間:2012年01月15日 23:44:23 作者:
本章我們要講解的是ECMAScript標準里的執(zhí)行上下文和相關(guān)可執(zhí)行代碼的各種類型
簡介
從本章開始,我將陸續(xù)(翻譯、轉(zhuǎn)載、整理)http://dmitrysoshnikov.com/網(wǎng)站關(guān)于ECMAScript標標準理解的好文。
本章我們要講解的是ECMAScript標準里的執(zhí)行上下文和相關(guān)可執(zhí)行代碼的各種類型。
原始作者:Dmitry A. Soshnikov
原始發(fā)布: 2009-06-26
俄文原文:http://dmitrysoshnikov.com/ecmascript/ru-chapter-1-execution-contexts/
英文翻譯:Dmitry A. Soshnikov.
發(fā)布時間:2010-03-11
英文翻譯:http://dmitrysoshnikov.com/ecmascript/chapter-1-execution-contexts/
本文參考了博客園justinw的中文翻譯,做了一些錯誤修正,感謝譯者。
復(fù)制代碼
定義
每次當控制器轉(zhuǎn)到ECMAScript可執(zhí)行代碼的時候,即會進入到一個執(zhí)行上下文。執(zhí)行上下文(簡稱-EC)是ECMA-262標準里的一個抽象概念,用于同可執(zhí)行代碼(executable code)概念進行區(qū)分。
標準規(guī)范沒有從技術(shù)實現(xiàn)的角度定義EC的準確類型和結(jié)構(gòu),這應(yīng)該是具體實現(xiàn)ECMAScript引擎時要考慮的問題。
活動的執(zhí)行上下文組在邏輯上組成一個堆棧。堆棧底部永遠都是全局上下文(global context),而頂部就是當前(活動的)執(zhí)行上下文。堆棧在EC類型進入和退出上下文的時候被修改(推入或彈出)。
可執(zhí)行代碼類型
可執(zhí)行代碼的類型這個概念與執(zhí)行上下文的抽象概念是有關(guān)系的。在某些時刻,可執(zhí)行代碼與執(zhí)行上下文完全有可能是等價的。
例如,我們可以定義執(zhí)行上下文堆棧是一個數(shù)組:
ECStack = [];
每次進入function (即使function被遞歸調(diào)用或作為構(gòu)造函數(shù)) 的時候或者內(nèi)置的eval函數(shù)工作的時候,這個堆棧都會被壓入。
全局代碼
這種類型的代碼是在"程序"級處理的:例如加載外部的js文件或者本地<script></script>標簽內(nèi)的代碼。全局代碼不包括任何function體內(nèi)的代碼。
在初始化(程序啟動)階段,ECStack是這樣的:
ECStack = [
globalContext
];
函數(shù)代碼
當進入funtion函數(shù)代碼(所有類型的funtions)的時候,ECStack被壓入新元素。需要注意的是,具體的函數(shù)代碼不包括內(nèi)部函數(shù)(inner functions)代碼。如下所示,我們使函數(shù)自己調(diào)自己的方式遞歸一次:
(function foo(bar) {
if (bar) {
return;
}
foo(true);
})();
那么,ECStack以如下方式被改變:
// 第一次foo的激活調(diào)用
ECStack = [
<foo> functionContext
globalContext
];
// foo的遞歸激活調(diào)用
ECStack = [
<foo> functionContext – recursively
<foo> functionContext
globalContext
];
每次return的時候,都會退出當前執(zhí)行上下文的,相應(yīng)地ECStack就會彈出,棧指針會自動移動位置,這是一個典型的堆棧實現(xiàn)方式。一個拋出的異常如果沒被截獲的話也有可能從一個或多個執(zhí)行上下文退出。相關(guān)代碼執(zhí)行完以后,ECStack只會包含全局上下文(global context),一直到整個應(yīng)用程序結(jié)束。
Eval 代碼
eval 代碼有點兒意思。它有一個概念: 調(diào)用上下文(calling context),例如,eval函數(shù)調(diào)用的時候產(chǎn)生的上下文。eval(變量或函數(shù)聲明)活動會影響調(diào)用上下文(calling context)。
eval('var x = 10');
(function foo() {
eval('var y = 20');
})();
alert(x); // 10
alert(y); // "y" 提示沒有聲明
ECStack的變化過程:
ECStack = [
globalContext
];
// eval('var x = 10');
ECStack.push(
evalContext,
callingContext: globalContext
);
// eval exited context
ECStack.pop();
// foo funciton call
ECStack.push(<foo> functionContext);
// eval('var y = 20');
ECStack.push(
evalContext,
callingContext: <foo> functionContext
);
// return from eval
ECStack.pop();
// return from foo
ECStack.pop();
也就是一個非常普通的邏輯調(diào)用堆棧。
在版本號1.7以上的SpiderMonkey(內(nèi)置于Firefox,Thunderbird)的實現(xiàn)中,可以把調(diào)用上下文作為第二個參數(shù)傳遞給eval。那么,如果這個上下文存在,就有可能影響“私有”(有人喜歡這樣叫它)變量。
function foo() {
var x = 1;
return function () { alert(x); };
};
var bar = foo();
bar(); // 1
eval('x = 2', bar); // 傳入上下文,影響了內(nèi)部的var x 變量
bar(); // 2
結(jié)論
這篇文章是后面分析其他跟執(zhí)行上下文相關(guān)的主題(例如變量對象,作用域鏈,等等)的最起碼的理論基礎(chǔ),這些主題將在后續(xù)章節(jié)中講到。
其他參考
從本章開始,我將陸續(xù)(翻譯、轉(zhuǎn)載、整理)http://dmitrysoshnikov.com/網(wǎng)站關(guān)于ECMAScript標標準理解的好文。
本章我們要講解的是ECMAScript標準里的執(zhí)行上下文和相關(guān)可執(zhí)行代碼的各種類型。
原始作者:Dmitry A. Soshnikov
原始發(fā)布: 2009-06-26
俄文原文:http://dmitrysoshnikov.com/ecmascript/ru-chapter-1-execution-contexts/
英文翻譯:Dmitry A. Soshnikov.
發(fā)布時間:2010-03-11
英文翻譯:http://dmitrysoshnikov.com/ecmascript/chapter-1-execution-contexts/
本文參考了博客園justinw的中文翻譯,做了一些錯誤修正,感謝譯者。
復(fù)制代碼
定義
每次當控制器轉(zhuǎn)到ECMAScript可執(zhí)行代碼的時候,即會進入到一個執(zhí)行上下文。執(zhí)行上下文(簡稱-EC)是ECMA-262標準里的一個抽象概念,用于同可執(zhí)行代碼(executable code)概念進行區(qū)分。
標準規(guī)范沒有從技術(shù)實現(xiàn)的角度定義EC的準確類型和結(jié)構(gòu),這應(yīng)該是具體實現(xiàn)ECMAScript引擎時要考慮的問題。
活動的執(zhí)行上下文組在邏輯上組成一個堆棧。堆棧底部永遠都是全局上下文(global context),而頂部就是當前(活動的)執(zhí)行上下文。堆棧在EC類型進入和退出上下文的時候被修改(推入或彈出)。
可執(zhí)行代碼類型
可執(zhí)行代碼的類型這個概念與執(zhí)行上下文的抽象概念是有關(guān)系的。在某些時刻,可執(zhí)行代碼與執(zhí)行上下文完全有可能是等價的。
例如,我們可以定義執(zhí)行上下文堆棧是一個數(shù)組:
ECStack = [];
每次進入function (即使function被遞歸調(diào)用或作為構(gòu)造函數(shù)) 的時候或者內(nèi)置的eval函數(shù)工作的時候,這個堆棧都會被壓入。
全局代碼
這種類型的代碼是在"程序"級處理的:例如加載外部的js文件或者本地<script></script>標簽內(nèi)的代碼。全局代碼不包括任何function體內(nèi)的代碼。
在初始化(程序啟動)階段,ECStack是這樣的:
復(fù)制代碼 代碼如下:
ECStack = [
globalContext
];
函數(shù)代碼
當進入funtion函數(shù)代碼(所有類型的funtions)的時候,ECStack被壓入新元素。需要注意的是,具體的函數(shù)代碼不包括內(nèi)部函數(shù)(inner functions)代碼。如下所示,我們使函數(shù)自己調(diào)自己的方式遞歸一次:
復(fù)制代碼 代碼如下:
(function foo(bar) {
if (bar) {
return;
}
foo(true);
})();
那么,ECStack以如下方式被改變:
復(fù)制代碼 代碼如下:
// 第一次foo的激活調(diào)用
ECStack = [
<foo> functionContext
globalContext
];
// foo的遞歸激活調(diào)用
ECStack = [
<foo> functionContext – recursively
<foo> functionContext
globalContext
];
每次return的時候,都會退出當前執(zhí)行上下文的,相應(yīng)地ECStack就會彈出,棧指針會自動移動位置,這是一個典型的堆棧實現(xiàn)方式。一個拋出的異常如果沒被截獲的話也有可能從一個或多個執(zhí)行上下文退出。相關(guān)代碼執(zhí)行完以后,ECStack只會包含全局上下文(global context),一直到整個應(yīng)用程序結(jié)束。
Eval 代碼
eval 代碼有點兒意思。它有一個概念: 調(diào)用上下文(calling context),例如,eval函數(shù)調(diào)用的時候產(chǎn)生的上下文。eval(變量或函數(shù)聲明)活動會影響調(diào)用上下文(calling context)。
復(fù)制代碼 代碼如下:
eval('var x = 10');
(function foo() {
eval('var y = 20');
})();
alert(x); // 10
alert(y); // "y" 提示沒有聲明
ECStack的變化過程:
復(fù)制代碼 代碼如下:
ECStack = [
globalContext
];
// eval('var x = 10');
ECStack.push(
evalContext,
callingContext: globalContext
);
// eval exited context
ECStack.pop();
// foo funciton call
ECStack.push(<foo> functionContext);
// eval('var y = 20');
ECStack.push(
evalContext,
callingContext: <foo> functionContext
);
// return from eval
ECStack.pop();
// return from foo
ECStack.pop();
也就是一個非常普通的邏輯調(diào)用堆棧。
在版本號1.7以上的SpiderMonkey(內(nèi)置于Firefox,Thunderbird)的實現(xiàn)中,可以把調(diào)用上下文作為第二個參數(shù)傳遞給eval。那么,如果這個上下文存在,就有可能影響“私有”(有人喜歡這樣叫它)變量。
復(fù)制代碼 代碼如下:
function foo() {
var x = 1;
return function () { alert(x); };
};
var bar = foo();
bar(); // 1
eval('x = 2', bar); // 傳入上下文,影響了內(nèi)部的var x 變量
bar(); // 2
結(jié)論
這篇文章是后面分析其他跟執(zhí)行上下文相關(guān)的主題(例如變量對象,作用域鏈,等等)的最起碼的理論基礎(chǔ),這些主題將在后續(xù)章節(jié)中講到。
其他參考
相關(guān)文章
javascript動態(tài)創(chuàng)建表格及添加數(shù)據(jù)實例詳解
這篇文章主要介紹了javascript動態(tài)創(chuàng)建表格及添加數(shù)據(jù),以實例形式分析了javascript動態(tài)創(chuàng)建表格的常用方法,包括不兼容IE6與兼容IE6的實現(xiàn)方法,非常具有實用價值,需要的朋友可以參考下2015-05-05微信小程序?qū)崿F(xiàn)導(dǎo)航欄選項卡效果
這篇文章主要為大家詳細介紹了微信小程序?qū)崿F(xiàn)導(dǎo)航欄選項卡效果,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-02-02Bootstrap開關(guān)(switch)控件學(xué)習(xí)筆記分享
這篇文章主要為大家分享了Bootstrap開關(guān)(switch)控件學(xué)習(xí)筆記,介紹了Bootstrap開關(guān)(switch)控件的功能、使用說明,感興趣的小伙伴們可以參考一下2016-05-05JavaScript擴展運算符的學(xué)習(xí)及應(yīng)用詳情(ES6)
這篇文章主要介紹了JavaScript擴展運算符的學(xué)習(xí)及應(yīng)用詳情(ES6),擴展運算符是ES6新增的一種運算符,他可以幫助我們簡化代碼,簡化操作,具體相關(guān)知識感興趣的小伙伴可以查看下面文章的簡單介紹2022-08-08百度地圖去掉marker覆蓋物或者去掉maker的label文字方法
下面小編就為大家分享一篇百度地圖去掉marker覆蓋物或者去掉maker的label文字方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-01-01微信公眾號生成新浪短網(wǎng)址的實現(xiàn)(快速生成)
這篇文章主要介紹了微信公眾號生成新浪短網(wǎng)址的實現(xiàn)(快速生成),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-08-08