2010-09-17 23 views
66

JavaScript程序由語句和函數聲明組成。執行JavaScript程序時,會發生以下兩個步驟:在瀏覽器中爲單個網頁執行多少個JavaScript程序?

  1. 將掃描代碼以查找函數聲明和每個函數。聲明是「執行」的(通過創建一個函數對象)並且創建了該函數的命名引用(以便可以從語句內調用該函數)

  2. 該語句按順序執行(評估)出現在代碼)

正因爲如此,這作品就好

<script> 
    foo(); 
    function foo() { 
     return; 
    } 
</script> 

雖然宣佈收到「foo」的函數被調用,它的工作原理是因爲好玩陳述聲明在聲明前被評估。

然而,這不起作用

<script> 
    foo(); 
</script> 
<script> 
    function foo() { 
     return; 
    } 
</script> 

一個的ReferenceError將被拋出( 「沒有定義富」)。 這導致了這樣的結論:網頁的HTML代碼中的每個SCRIPT元素代表一個單獨的JavaScript程序,並且每當HTML分析器遇到SCRIPT元素時,它就執行該元素內的程序(然後一旦程序被執行,解析器移到跟在SCRIPT元素後面的HTML代碼中)。

然後,這種確實工作

<script> 
    function foo() { 
     return; 
    } 
</script> 
<script> 
    foo(); 
</script> 

我的理解這裏要說的是全局對象(其作爲在全球執行上下文的變量對象)存在(並保持)在任何時候,所以第一個JavaScript程序將創建函數對象併爲其創建引用,然後第二個JavaScript程序將使用該引用來調用該函數。因此,所有JavaScript程序(在單個網頁內)「使用」相同的全局對象,所有JavaScript程序所做的所有更改都可以被後續運行的所有JavaScript程序觀察到。

現在,注意到這...

<script> 
    // assuming that foo is not defined 
    foo(); 
    alert(1); 
</script> 

在上述情況下,報警電話不會執行,因爲「富()」語句拋出一個的ReferenceError(它打破了整個JavaScript程序),因此,所有後續的語句都不執行。

然而,在這種情況下...

<script> 
    // assuming that foo is not defined 
    foo(); 
</script> 
<script> 
    alert(1); 
</script> 

現在,警報呼叫沒有得到執行。第一個JavaScript程序拋出一個ReferenceError(並因此中斷),但第二個JavaScript程序正常運行。當然,瀏覽器會報告錯誤(儘管它在發生錯誤後執行了後續的JavaScript程序)。

現在,我的結論是:

  • 的網頁的HTML代碼中的每個SCRIPT元素代表一個獨立的JavaScript程序。這些程序在HTML解析器遇到它們時立即執行。
  • 同一網頁中的所有JavaScript程序「使用」相同的全局對象。該Global對象始終存在(從網頁被提取到網頁被銷燬的那一刻)。 JavaScript程序可能會操縱Global對象,並且可以在所有後續的JavaScript程序中觀察到由一個JavaScript程序對Global對象所做的所有更改。
  • 如果一個JavaScript程序中斷(通過拋出錯誤),這並不妨礙後續的JavaScript程序執行。

請其實檢查這篇文章,並告訴我,如果我得到了什麼。

此外,我還沒有找到解釋本文中提到的行爲的資源,我假設瀏覽器製造商必須在某處發佈此類資源,因此如果您瞭解這些資源,請提供指向它們的鏈接。

更新!

OK,我要(試圖)從梅德A. Soshnikov這裏回答我的問題:) 我得到了(通過電子郵件)的響應(他經營着一個關於JavaScript的博客在http://www.dmitrysoshnikov.com/)。

他在這個問題上是這樣的:每個腳本塊包含全局代碼。執行每個SCRIPT塊會創建一個新的執行上下文。因此,每個SCRIPT塊都有自己的執行上下文,但所有這些執行上下文共享同一個全局對象。

SCRIPT塊可以被看作是不同的「子節目」具有相同的共享狀態。

此外,ECMAScript規範(第3版)規定(第10章): 「全局代碼是被視爲ECMAScript程序的源文本。」

回答

14

梅德Soshnikov已經回答了你的問題。按照ECMAScript規範的定義,每個<script>元素都作爲程序執行。每個程序在單個頁面中使用一個全局對象。而這就是它。

7

他們是獨立的程序,但他們修改共享全局對象。

19

函數提升 - 在函數其餘部分之前評估function語句的過程 - 是ECMAScript標準IIRC的一部分(我現在找不到引用,但我記得看過提及它的EMCAScript的討論)。 script標籤的評估是HTML標準的一部分。它沒有用這麼多的單詞來指定它們是「單獨的程序」,但它確實表示腳本元素按它們在文檔中出現的順序進行評估。這就是爲什麼後面的腳本標記中的函數沒有被掛起:腳本尚未被評估。這也解釋了爲什麼一個腳本停止不會切斷後續腳本:當前腳本停止評估時,下一個腳本開始。

+0

鏈接解釋HOISTING。 http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting – Rajat 2010-10-14 21:02:26

4

另一種方式來思考,這是僞當地VS全局範圍。每個SCRIPT聲明對當前的方法/函數都具有局部範圍,並且可以訪問當前(以前聲明的)全局範圍。無論何時在SCRIPT塊中定義一個方法/函數,它都會被添加到全局範圍,並且可以在SCRIPT塊之後被SCRIPT塊訪問。

另外,這裏是從W3C上腳本聲明/處理/變形例的進一步的參考:

文檔 可以被建模爲的動態修改如下:

  1. 所有SCRIPT元件被評估爲了加載文檔。
  2. 評估給定SCRIPT元素內生成 SGML CDATA的所有腳本構造。將他們的 組合生成的文本插入 文件中,代替SCRIPT 元素。
  3. 生成的CDATA被重新評估。

This是腳本/功能評價/聲明另一個很好的資源。

相關問題