理解Javascript_12_執(zhí)行模型淺析
更新時間:2010年10月18日 00:51:34 作者:
大家有沒有想過,一段javascript腳本從載入瀏覽器到顯示執(zhí)行都經(jīng)過了哪些流程,其執(zhí)行次序又是如何。本篇博文將引出'javascript執(zhí)行模型'的概念,并帶領(lǐng)大家理解javascript在執(zhí)行時的處理機制。
簡單的開始
簡單的代碼:
<script type="text/javascript" src="xxx.js"></script>
<script type="text/javascript">
var i = 10;
function say(msg){
alert(msg);
}
</script>
<script type="text/javascript">
j=100;
say("hello world");
</script>
上面代碼段的運行順序是:
step1. 讀入第一個代碼段
step2. 做語法分析,有錯則報語法錯誤(比如括號不匹配等),并跳轉(zhuǎn)到step5
step3. 創(chuàng)建全局執(zhí)行環(huán)境(對var變量和function定義做"預(yù)解析")
step4. 執(zhí)行代碼段(調(diào)用函數(shù)、進入eval時,都會創(chuàng)建新的執(zhí)行環(huán)境),有錯則報錯(比如變量未定義)
step5. 如果還有下一個代碼段,則讀入下一個代碼段,重復(fù)step2
step6. 結(jié)束
對于step1中的'腳本段'指的是<script>... ...</script>標簽中的內(nèi)容,還包括外部引入的腳本文件,如<script src="xxx.js"></script>也被列是腳本段的范疇。那step2中的語法分析又是什么呢?簡單的理解語法分析就是查看Javascript代碼的語法結(jié)構(gòu)是否正確。如:
<script type="text/javascript">
var a = 10;
if(a>10{
alert('yes');
}
</script>
很明顯,代碼無法通過語法分析,if這個條件語句的輸寫語法是錯誤的。step3和step4中的'執(zhí)行環(huán)境'是指什么,全局執(zhí)行環(huán)境和調(diào)用函數(shù)創(chuàng)建的執(zhí)行環(huán)境有什么區(qū)別?執(zhí)行環(huán)境內(nèi)部又有哪些處理?... ...
注:下面的部分內(nèi)容為原來《javascript提速_01_引用變量優(yōu)化》一文中的前兩節(jié)的完整版本。
關(guān)于執(zhí)行環(huán)境(Execution Context)
所有 JavaScript 代碼都是在一個執(zhí)行環(huán)境中被執(zhí)行的。它是一個概念,一種機制,用來完成JavaScript運行時作用域、生存期等方面的處理。
可執(zhí)行的JavaScript代碼分三種類型:
1. Global Code,即全局的、不在任何函數(shù)里面的代碼,例如:一個js文件、嵌入在HTML頁面中的js代碼等。
2. Eval Code,即使用eval()函數(shù)動態(tài)執(zhí)行的JS代碼。
3. Function Code,即用戶自定義函數(shù)中的函數(shù)體JS代碼。
不同類型的JavaScript代碼具有不同的Execution Context
在一個頁面中,第一次載入JS代碼時創(chuàng)建一個全局執(zhí)行環(huán)境,當調(diào)用一個 JavaScript 函數(shù)時,該函數(shù)就會進入相應(yīng)的執(zhí)行環(huán)境。如果又調(diào)用了另外一個函數(shù)(或者遞歸地調(diào)用同一個函數(shù)),則又會創(chuàng)建一個新的執(zhí)行環(huán)境,并且在函數(shù)調(diào)用期間執(zhí)行過程都處于該環(huán)境中。當調(diào)用的函數(shù)返回后,執(zhí)行過程會返回原始執(zhí)行環(huán)境。因而,運行中的 JavaScript 代碼就構(gòu)成了一個執(zhí)行環(huán)境棧。
讓我們來看一個示例:
<script type="text/javascript">
function Fn1(){
function Fn2(){
alert(document.body.tagName);//BODY
//other code...
}
Fn2();
}
Fn1();
//code here
</script>

以上是程序從上到下執(zhí)行時的執(zhí)行環(huán)境棧情況圖。
補充說明:
全局執(zhí)行環(huán)境對應(yīng)的是Global Code(全局代碼)
Fn1執(zhí)行環(huán)境、Fn2執(zhí)行環(huán)境通稱為函數(shù)執(zhí)行環(huán)境對應(yīng)的是Function Code(函數(shù)定義代碼)
程序在進入每個執(zhí)行環(huán)境的時候都會創(chuàng)建一個叫做Variable Object的對象。
針對于函數(shù)執(zhí)行環(huán)境,函數(shù)對應(yīng)的每一個參數(shù)、局部變量、內(nèi)部方法都會在Variable Object上創(chuàng)建一個屬性,屬性名為變量名,屬性值為變量值。針對于全局執(zhí)行環(huán)境,具有相同的行為。但是要強調(diào)的一點是在全局執(zhí)行環(huán)境中Varible Object就是Global Object,關(guān)于Global Object在《理解Javascript_03_javascript全局觀》中已經(jīng)說明了,可以簡單的理解為window對象。這也就解釋了全局方法和全局變量為什么都是window對象的屬性或方法的原因,請看如下代碼:
var num = 123;
alert(window.num);//123
function say(msg){
alert(msg);
}
window.say("hello");//hello
最后要說的是,Variable Object對象是一個內(nèi)部對象,JS代碼中無法直接訪問。
關(guān)于Scope/Scope Chain
在訪問變量時,就必須存在一個可見性的問題,這就是Scope。更深入的說,當訪問一個變量或調(diào)用一個函數(shù)時,JavaScript引擎將不同執(zhí)行位置上的Variable Object按照規(guī)則構(gòu)建一個鏈表,在訪問一個變量時,先在鏈表的第一個Variable Object上查找,如果沒有找到則繼續(xù)在第二個Variable Object上查找,直到搜索結(jié)束。這也就形成了Scope Chain的概念。

作用域鏈圖,清楚的表達了執(zhí)行環(huán)境與作用域的關(guān)系(一一對應(yīng)的關(guān)系),作用域與作用域之間的關(guān)系(鏈表結(jié)構(gòu),由上至下的關(guān)系)。
注:本文僅僅從全局角度的看待javascript執(zhí)行模型,因此不夠深入,具體執(zhí)行細節(jié),請參見后續(xù)博文。
參考:
http://www.cnblogs.com/RicCC/archive/2008/02/15/JavaScript-Object-Model-Execution-Model.html
http://www.cn-cuckoo.com/2007/08/01/understand-javascript-closures-72.html
http://lifesinger.org/blog/2009/01/javascript-run-mechanism/
簡單的代碼:
復(fù)制代碼 代碼如下:
<script type="text/javascript" src="xxx.js"></script>
<script type="text/javascript">
var i = 10;
function say(msg){
alert(msg);
}
</script>
<script type="text/javascript">
j=100;
say("hello world");
</script>
上面代碼段的運行順序是:
復(fù)制代碼 代碼如下:
step1. 讀入第一個代碼段
step2. 做語法分析,有錯則報語法錯誤(比如括號不匹配等),并跳轉(zhuǎn)到step5
step3. 創(chuàng)建全局執(zhí)行環(huán)境(對var變量和function定義做"預(yù)解析")
step4. 執(zhí)行代碼段(調(diào)用函數(shù)、進入eval時,都會創(chuàng)建新的執(zhí)行環(huán)境),有錯則報錯(比如變量未定義)
step5. 如果還有下一個代碼段,則讀入下一個代碼段,重復(fù)step2
step6. 結(jié)束
對于step1中的'腳本段'指的是<script>... ...</script>標簽中的內(nèi)容,還包括外部引入的腳本文件,如<script src="xxx.js"></script>也被列是腳本段的范疇。那step2中的語法分析又是什么呢?簡單的理解語法分析就是查看Javascript代碼的語法結(jié)構(gòu)是否正確。如:
復(fù)制代碼 代碼如下:
<script type="text/javascript">
var a = 10;
if(a>10{
alert('yes');
}
</script>
很明顯,代碼無法通過語法分析,if這個條件語句的輸寫語法是錯誤的。step3和step4中的'執(zhí)行環(huán)境'是指什么,全局執(zhí)行環(huán)境和調(diào)用函數(shù)創(chuàng)建的執(zhí)行環(huán)境有什么區(qū)別?執(zhí)行環(huán)境內(nèi)部又有哪些處理?... ...
注:下面的部分內(nèi)容為原來《javascript提速_01_引用變量優(yōu)化》一文中的前兩節(jié)的完整版本。
關(guān)于執(zhí)行環(huán)境(Execution Context)
所有 JavaScript 代碼都是在一個執(zhí)行環(huán)境中被執(zhí)行的。它是一個概念,一種機制,用來完成JavaScript運行時作用域、生存期等方面的處理。
可執(zhí)行的JavaScript代碼分三種類型:
1. Global Code,即全局的、不在任何函數(shù)里面的代碼,例如:一個js文件、嵌入在HTML頁面中的js代碼等。
2. Eval Code,即使用eval()函數(shù)動態(tài)執(zhí)行的JS代碼。
3. Function Code,即用戶自定義函數(shù)中的函數(shù)體JS代碼。
不同類型的JavaScript代碼具有不同的Execution Context
在一個頁面中,第一次載入JS代碼時創(chuàng)建一個全局執(zhí)行環(huán)境,當調(diào)用一個 JavaScript 函數(shù)時,該函數(shù)就會進入相應(yīng)的執(zhí)行環(huán)境。如果又調(diào)用了另外一個函數(shù)(或者遞歸地調(diào)用同一個函數(shù)),則又會創(chuàng)建一個新的執(zhí)行環(huán)境,并且在函數(shù)調(diào)用期間執(zhí)行過程都處于該環(huán)境中。當調(diào)用的函數(shù)返回后,執(zhí)行過程會返回原始執(zhí)行環(huán)境。因而,運行中的 JavaScript 代碼就構(gòu)成了一個執(zhí)行環(huán)境棧。
讓我們來看一個示例:
復(fù)制代碼 代碼如下:
<script type="text/javascript">
function Fn1(){
function Fn2(){
alert(document.body.tagName);//BODY
//other code...
}
Fn2();
}
Fn1();
//code here
</script>

以上是程序從上到下執(zhí)行時的執(zhí)行環(huán)境棧情況圖。
補充說明:
全局執(zhí)行環(huán)境對應(yīng)的是Global Code(全局代碼)
Fn1執(zhí)行環(huán)境、Fn2執(zhí)行環(huán)境通稱為函數(shù)執(zhí)行環(huán)境對應(yīng)的是Function Code(函數(shù)定義代碼)
程序在進入每個執(zhí)行環(huán)境的時候都會創(chuàng)建一個叫做Variable Object的對象。
針對于函數(shù)執(zhí)行環(huán)境,函數(shù)對應(yīng)的每一個參數(shù)、局部變量、內(nèi)部方法都會在Variable Object上創(chuàng)建一個屬性,屬性名為變量名,屬性值為變量值。針對于全局執(zhí)行環(huán)境,具有相同的行為。但是要強調(diào)的一點是在全局執(zhí)行環(huán)境中Varible Object就是Global Object,關(guān)于Global Object在《理解Javascript_03_javascript全局觀》中已經(jīng)說明了,可以簡單的理解為window對象。這也就解釋了全局方法和全局變量為什么都是window對象的屬性或方法的原因,請看如下代碼:
復(fù)制代碼 代碼如下:
var num = 123;
alert(window.num);//123
function say(msg){
alert(msg);
}
window.say("hello");//hello
最后要說的是,Variable Object對象是一個內(nèi)部對象,JS代碼中無法直接訪問。
關(guān)于Scope/Scope Chain
在訪問變量時,就必須存在一個可見性的問題,這就是Scope。更深入的說,當訪問一個變量或調(diào)用一個函數(shù)時,JavaScript引擎將不同執(zhí)行位置上的Variable Object按照規(guī)則構(gòu)建一個鏈表,在訪問一個變量時,先在鏈表的第一個Variable Object上查找,如果沒有找到則繼續(xù)在第二個Variable Object上查找,直到搜索結(jié)束。這也就形成了Scope Chain的概念。

作用域鏈圖,清楚的表達了執(zhí)行環(huán)境與作用域的關(guān)系(一一對應(yīng)的關(guān)系),作用域與作用域之間的關(guān)系(鏈表結(jié)構(gòu),由上至下的關(guān)系)。
注:本文僅僅從全局角度的看待javascript執(zhí)行模型,因此不夠深入,具體執(zhí)行細節(jié),請參見后續(xù)博文。
參考:
http://www.cnblogs.com/RicCC/archive/2008/02/15/JavaScript-Object-Model-Execution-Model.html
http://www.cn-cuckoo.com/2007/08/01/understand-javascript-closures-72.html
http://lifesinger.org/blog/2009/01/javascript-run-mechanism/
相關(guān)文章
JS結(jié)合bootstrap實現(xiàn)基本的增刪改查功能
這篇文章主要介紹了JS結(jié)合bootstrap實現(xiàn)基本的增刪改查功能,需要的朋友可以參考下2016-07-07基于JavaScript實現(xiàn)實時在線協(xié)作編輯器
隨著Web技術(shù)的發(fā)展,實現(xiàn)在線協(xié)作編輯文檔已經(jīng)成為一種常見的需求,本文主要為大家詳細介紹了如何使用JavaScript實現(xiàn)實時在線協(xié)作編輯器,需要的可以參考下2024-01-01用javascript實現(xiàn)給出的盒子的序列是否可連為一矩型
用javascript實現(xiàn)給出的盒子的序列是否可連為一矩型...2007-08-08javascript + jquery實現(xiàn)定時修改文章標題
用javascript+jquery寫的一個定時器,定時修改文章標題,需要的朋友可以參考下2014-03-03JS中關(guān)于事件處理函數(shù)名后面是否帶括號的問題
JS中的事件處理(事件綁定)就是讓某種或某些事件觸發(fā)某些活動。有兩種常見的形式,分別是DOM Level 0 和DOM Level 2。今天總結(jié)一個關(guān)于事件處理程序的小細節(jié)。感興趣的朋友一起學(xué)習(xí)吧2016-11-11關(guān)于微信小程序中使用wx.getLocation獲取當前詳細位置并計算距離
這篇文章主要介紹了關(guān)于微信小程序中使用wx.getLocation獲取當前詳細位置并計算距離,wx.getLocation只能夠獲取經(jīng)緯度,不能夠拿到詳細地址,這里使用騰訊地圖的api,需要的朋友可以參考下2023-04-04