<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    淺談JavaScript 的運行機理

    ——hechangmin@gmail.com  2010.10

    這個話題看似簡單,其實筆者是幾次三番的下筆,又幾次三番的放棄。因為這個內容,對于很多JavaScript的開發人員來講都是一知半解的,當然筆者也在其中,今天之所以出來獻丑了,首先是有了更深的認識,其次微博上有人說獻丑是進步,如果獻丑那必定是有同道之人能指出紕漏,那對于筆者本人來講何嘗不是進步呢?深表贊同!

    今天會以幾個小小的實例來解讀這個課題。希望能與大家共勉。

    首先得先了解JavaScript執行起來的流程,筆者先簡單畫了一個javascript的執行流程圖:



    重點解釋的有三步:詞法分析、預解析、執行。

    script代碼段:用script標簽分隔的js代碼或引入的js文件。

    (1). 預解析

    我們先從幾個常見的javascript 小題目入手,請大家先看看下面的范例輸出什么?

    <script type="text/javascript">

        alert(i); // ?

        var i = 1;

    </script>

    對于javascript的從業者可以試著運行下。看看你的答案和實際輸出一致嗎?別小看這樣兩行腳本,這樣的題目被當作JavaScript的筆試或者面試題目是常有的事情。

    實際輸出結果為:“undefined”,

    這種現象被稱成預解析JavaScript腳本引擎優先解析var變量和function定義。在預解析完成后,才會執行代碼。

    由于變量是被 var聲明的,而被優先解析。所以可以理解為在 alert(i) 執行時候,程序前面已經有 var i;

    所以上面代碼等效解釋為:

    <script type="text/javascript">

        var i;

    alert(i); // 對于被聲明,但未賦值過的i,輸出‘undefined’的結果,是不應該有任何歧義了吧。

        i = 1;

    </script>

    注意:預解析不會報錯,因為他只解析正確的聲明。

    (2). 解釋(主要指詞法分析,生成語法樹的過程)

    請注意,這里‘解釋’的定義是筆者自己方便理解自己定義的,而這個‘解釋’并不在預解析之后。

    我們知道JavaScript是腳本語言,腳本語言是相對于高級編譯型語言而言他是解釋性的。解釋性語言沒有編譯成二進制代碼,但是要進入到運行階段,都應該是會經過詞法分析、語法分析生成語法樹、語義檢查過程,筆者把這個環節叫做解釋,如果讀者有更科學的名字記得告訴我。

    解釋性語言在生成語法樹后,就可以執行了。(這個跟腳本引擎編譯器有關)

    在這個過程中,有語法檢查(比如括號是否匹配),發現無法生成語法樹,則報錯,結束整個代碼塊的解析。

    (3) 執行 與 作用域

    引入我們的第二個示例代碼:

    <script type="text/javascript">

        alert(i); // error: i is not defined.

        i = 1;

    </script>

    聽說JavaScript 變量可以直接用,那為什么還報運行時腳本錯誤?—— i 未定義.

    執行過程,需要理解JavaScript的作用域機制,JavaScript變量的作用域是在定義時決定而不是執行時決定,也就是說詞法作用域取決于源碼,編譯器通過靜態分析就能確定,因此詞法作用域也叫做靜態作用域(static scope)。但需要注意,witheval的語義無法僅通過靜態技術實現,實際上,只能說JS的作用域機制非常接近lexical scope.

    JS引擎在執行每個函數實例時,都會創建一個執行環境(execution context)。execution context中包含一個調用對象(call object調用對象是一個scriptObject結構,用來保存內部變量表varDecls、內嵌函數表funDecls、父級引用列表upvalue等語法分析結構(注意:varDeclsfunDecls等信息是在預解析階段就已經得到,并保存在語法樹中。函數實例執行時,會將這些信息從語法樹復制到scriptObject上)。scriptObject是與函數相關的一套靜態系統,與函數實例的生命周期保持一致。

    lexical scopeJS的作用域機制,還需要理解它的實現方法,這就是作用域鏈(scope chain)。scope chain是一個name lookup機制,首先在當前執行環境的scriptObject中尋找,沒找到,則順著upvalue到父級scriptObject中尋找,一直lookup到全局調用對象(global object)。

    當一個函數實例執行時,會創建或關聯到一個閉包(closure)。 scriptObject用來靜態保存與函數相關的變量表,closure則在執行期動態保存這些變量表及其運行值。closure的生命周期有可能比函數實例長。函數實例在活動引用為空后會自動銷毀,closure則要等要數據引用為空后,由JS引擎回收(有些情況下不會自動回收,就導致了內存泄漏)。

    別被上面的一堆名詞嚇住,一旦理解了執行環境、調用對象、閉包、詞法作用域、作用域鏈這些概念,JS語言的很多現象都能迎刃而解。

    小結

    預解析,其實是在的‘解釋’階段完成,并存儲在語法樹中。當執行到函數實例時,會將varDelcsfuncDecls從語法樹中復制到執行環境的scriptObject上。

    對于示例解析:

    未定義變量意味著在scriptObject的變量表中找不到,JS引擎會沿著scriptObjectupvalue往上尋找,如果都沒找到,對于寫操作i = 1; 最后就會等價為 window.i = 1; window對象新增了一個屬性。對于讀操作,如果一直追溯到全局執行環境的scriptObject上都找不到,就會產生運行期錯誤。

    最后,留個問題給大家:

    <script type="text/javascript">

        var arg = 1;

        function foo(arg) {

            alert(arg);

            var arg = 2;

        }

        foo(3);

    </script>

    請問alert的輸出是什么?

    posted on 2010-10-09 01:21 -274°C 閱讀(2281) 評論(0)  編輯  收藏 所屬分類: web前端

    常用鏈接

    留言簿(21)

    隨筆分類(265)

    隨筆檔案(242)

    相冊

    JAVA網站

    關注的Blog

    搜索

    •  

    積分與排名

    • 積分 - 914354
    • 排名 - 40

    最新評論

    主站蜘蛛池模板: 天黑黑影院在线观看视频高清免费 | 久久久久亚洲AV成人网人人软件| 亚洲午夜久久久久久久久电影网| japanese色国产在线看免费| xvideos亚洲永久网址| 免费看黄福利app导航看一下黄色录像| 国产高清免费观看| 黄色免费网站在线看| AV在线播放日韩亚洲欧| 久久免费99精品国产自在现线| 亚洲中文字幕无码一区 | 91亚洲国产成人久久精品| 1000部拍拍拍18勿入免费视频软件 | 成人在线免费看片| 亚洲一区二区三区在线| 免费无码黄网站在线观看| 污污免费在线观看| 亚洲A∨无码一区二区三区| 91网站免费观看| 亚洲乱亚洲乱妇无码| 亚洲国产一区二区三区| 国产拍拍拍无码视频免费| 亚洲av无码专区国产乱码在线观看| 久久久精品免费国产四虎| 亚洲三级在线播放| 免费观看四虎精品国产永久 | 久久久久av无码免费网| 亚洲国产日韩综合久久精品| 国产a不卡片精品免费观看| 中文字幕成人免费高清在线视频| 久久亚洲日韩精品一区二区三区| 最新中文字幕电影免费观看| 色老头综合免费视频| 久久亚洲精品无码AV红樱桃| 国产成人啪精品视频免费网| 久久久国产精品福利免费| 亚洲欧美国产精品专区久久| 亚洲精品无码午夜福利中文字幕| 男人的好免费观看在线视频| 一区二区三区免费视频网站| 亚洲va在线va天堂va手机|