<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

    最新評論

    主站蜘蛛池模板: 中文字幕免费在线观看动作大片| 国产亚洲高清在线精品不卡| 毛片在线全部免费观看| 亚洲精品午夜国产VA久久成人 | 在线a亚洲老鸭窝天堂av高清| 69式互添免费视频| 67194在线午夜亚洲| 69式国产真人免费视频| 亚洲中文字幕AV每天更新| 日韩免费高清一级毛片在线| 亚洲国产AV一区二区三区四区| 日韩激情无码免费毛片| 九九九精品视频免费| 久久亚洲成a人片| 日韩欧毛片免费视频| 亚洲AV综合色区无码一二三区 | 日韩视频在线精品视频免费观看 | 美女免费视频一区二区| 国产亚洲av人片在线观看| 国产成人AV免费观看| 亚洲欧洲国产综合| 免费看国产精品麻豆| a毛片在线看片免费| 亚洲啪啪免费视频| 国产免费AV片无码永久免费| 青柠影视在线观看免费高清| 亚洲成a人片毛片在线| 国产一级一片免费播放i| 男人都懂www深夜免费网站| 亚洲an日韩专区在线| 亚洲日韩在线中文字幕第一页| 无码少妇精品一区二区免费动态| 亚洲福利一区二区精品秒拍| 成人免费视频一区二区三区| 一级中文字幕乱码免费| 日木av无码专区亚洲av毛片| 精品久久久久久久免费人妻| 精品四虎免费观看国产高清午夜| 在线综合亚洲中文精品| 亚洲综合色自拍一区| 最近免费中文字幕大全视频|