最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

JavaScript執(zhí)行順序詳細介紹

 更新時間:2013年12月04日 17:10:08   作者:  
這篇文章主要介紹了JavaScript執(zhí)行順序,有需要的朋友可以參考一下

之前從JavaScript引擎的解析機制來探索JavaScript的工作原理,下面我們以更形象的示例來說明JavaScript代碼在頁面中的執(zhí)行順序。如果說,JavaScript引擎的工作機制比較深奧是因為它屬于底層行為,那么JavaScript代碼執(zhí)行順序就比較形象了,因為我們可以直觀感覺到這種執(zhí)行順序,當然JavaScript代碼的執(zhí)行順序是比較復雜的,所以在深入JavaScript語言之前也有必要對其進行剖析。
1.1  按HTML文檔流順序執(zhí)行JavaScript代碼
首先,讀者應該清楚,HTML文檔在瀏覽器中的解析過程是這樣的:瀏覽器是按著文檔流從上到下逐步解析頁面結構和信息的。JavaScript代碼作為嵌入的腳本應該也算做HTML文檔的組成部分,所以JavaScript代碼在裝載時的執(zhí)行順序也是根據(jù)腳本標簽<script>的出現(xiàn)順序來確定的。例如,瀏覽下面文檔頁面,你會看到代碼是從上到下逐步被解析的。

復制代碼 代碼如下:

<script>
alert("頂部腳本");
</script>
<html><head>
<script>
alert("頭部腳本");
</script>
<title></title>
</head>
<body>
<script>
alert("頁面腳本");
</script>
</body></html>
<script>
alert("底部腳本");
</script>

如果通過腳本標簽<script>的src屬性導入外部JavaScript文件腳本,那么它也將按照其語句出現(xiàn)的順序來執(zhí)行,而且執(zhí)行過程是文檔裝載的一部分。不會因為是外部JavaScript文件而延期執(zhí)行。例如,把上面文檔中的頭部和主體區(qū)域的腳本移到外部JavaScript文件中,然后通過src屬性導入。繼續(xù)預覽頁面文檔,你會看到相同的執(zhí)行順序。

復制代碼 代碼如下:

<script>

alert("頂部腳本");

</script>

<html>

<head>

<script src="http://www.fzitv.net/head.js"></script>

<title></title>

</head>

<body>

<script src="http://www.fzitv.net/body.js"></script>

</body>

</html>

<script>

alert("底部腳本");

</script>

1.2  預編譯與執(zhí)行順序的關系

在Javascript中,function才是Javascript的第一型。當我們寫下一段函數(shù)時,其實不過是建立了一個function類型的實體。
就像我們可以寫成這樣的形式一樣:

復制代碼 代碼如下:

functionHello()
{
alert("Hello");
}
Hello();
varHello = function()
{
alert("Hello");
}
Hello();

其實都是一樣的。 但是當我們對其中的函數(shù)進行修改時,會發(fā)現(xiàn)很奇怪的問題。
復制代碼 代碼如下:

<scripttype="text/javascript">       
functionHello() {        
alert("Hello");  
}       
Hello();     
functionHello() {  
alert("Hello World");   
}       
Hello();   
</script>

我們會看到這樣的結果:連續(xù)輸出了兩次Hello World。
而非我們想象中的Hello和Hello World。
這是因為Javascript并非完全的按順序解釋執(zhí)行,而是在解釋之前會對Javascript進行一次“預編譯”,在預編譯的過程中,會把定義式的函數(shù)優(yōu)先執(zhí)行,也會把所有var變量創(chuàng)建,默認值為undefined,以提高程序的執(zhí)行效率。
也就是說上面的一段代碼其實被JS引擎預編譯為這樣的形式:
復制代碼 代碼如下:

<scripttype="text/javascript">       
varHello = function() {          
alert("Hello");       
}      
Hello = function() {
           alert("Hello World"); 
      }     
Hello();    
Hello(); 
</script>

我們可以通過上面的代碼很清晰地看到,其實函數(shù)也是數(shù)據(jù),也是變量,我們也可以對“函數(shù)“進行賦值(重賦值)。
當然,我們?yōu)榱朔乐惯@樣的情況,也可以這樣:
復制代碼 代碼如下:

<scripttype="text/javascript">     
functionHello() {       
alert("Hello");      
}       
Hello(); 
</script>  
<scripttype="text/javascript">  
functionHello() {         
alert("Hello World");    
}      
Hello(); 
</script>

這樣,程序被分成了兩段,JS引擎也就不會把他們放到一起了。   

當JavaScript引擎解析腳本時,它會在預編譯期對所有聲明的變量和函數(shù)進行處理。

做如下處理:

1. 在執(zhí)行前會進行類似“預編譯”的操作:首先會創(chuàng)建一個當前執(zhí)行環(huán)境下的活動對象,并將那些用var申明的變量設置為活動對象的屬性,但是此時這些變量的賦值都是undefined,并將那些以function定義的函數(shù)也添加為活動對象的屬性,而且它們的值正是函數(shù)的定義。

2. 在解釋執(zhí)行階段,遇到變量需要解析時,會首先從當前執(zhí)行環(huán)境的活動對象中查找,如果沒有找到而且該執(zhí)行環(huán)境的擁有者有prototype屬性時則會從prototype鏈中查找,否則將會按照作用域鏈查找。遇到var a = ...這樣的語句時會給相應的變量進行賦值(注意:變量的賦值是在解釋執(zhí)行階段完成的,如果在這之前使用變量,它的值會是undefined) 所以,就會出現(xiàn)當JavaScript解釋器執(zhí)行下面腳本時不會報錯:

復制代碼 代碼如下:

alert(a);                            // 返回值undefined

var a =1;

alert(a);                            // 返回值1


由于變量聲明是在預編譯期被處理的,所以在執(zhí)行期間對于所有代碼來說,都是可見的。但是,你也會看到,執(zhí)行上面代碼,提示的值是undefined,而不是1。這是因為,變量初始化過程發(fā)生在執(zhí)行期,而不是預編譯期。在執(zhí)行期,JavaScript解釋器是按著代碼先后順序進行解析的,如果在前面代碼行中沒有為變量賦值,則JavaScript解釋器會使用默認值undefined。由于在第二行中為變量a賦值了,所以在第三行代碼中會提示變量a的值為1,而不是undefined。

同理,下面示例在函數(shù)聲明前調用函數(shù)也是合法的,并能夠被正確解析,所以返回值為1。

復制代碼 代碼如下:

f();                                 // 調用函數(shù),返回值1

function f(){

    alert(1);

}

但是,如果按下面方式定義函數(shù),則JavaScript解釋器會提示語法錯誤。

復制代碼 代碼如下:

f();                                 // 調用函數(shù),返回語法錯誤

var f = function(){

    alert(1);

}

這是因為,上面示例中定義的函數(shù)僅作為值賦值給變量f,所以在預編譯期,JavaScript解釋器只能夠為聲明變量f進行處理,而對于變量f的值,只能等到執(zhí)行期時按順序進行賦值,自然就會出現(xiàn)語法錯誤,提示找不到對象f。

再見一些例子:

復制代碼 代碼如下:

<script type="text/javascript">

/*在預編譯過程中func是window環(huán)境下的活動對象中的一個屬性,值是一個函數(shù),覆蓋了undefined值*/

alert(func); //function func(){alert("hello!")}

var func = "this is a variable"

function func(){

alert("hello!")

}

/*在執(zhí)行過程中遇到了var重新賦值為"this is a variable"*/

alert(func);  //this is a variable

</script>

復制代碼 代碼如下:

<script type="text/javascript">
var name = "feng"; function func()
{
/*首先,在func環(huán)境內先把name賦值為undefined,然后在執(zhí)行過程中先尋找func環(huán)境下的活動對象的name屬性,此時之前已經(jīng)預編譯值為undefined,所以輸出是undefined,而不是feng*/
alert(name);  //undefined var name = "JSF";
alert(name);  //JSF
}
func();
alert(name);
//feng
</script>

雖然變量和函數(shù)聲明可以在文檔任意位置,但是良好的習慣應該是在所有JavaScript代碼之前聲明全局變量和函數(shù),并對變量進行初始化賦值。在函數(shù)內部也是先聲明變量,然后再引用。

1.3  按塊執(zhí)行JavaScript代碼

所謂代碼塊就是使用<script>標簽分隔的代碼段。例如,下面兩個<script>標簽分別代表兩個JavaScript代碼塊。

復制代碼 代碼如下:

<script>

// JavaScript代碼塊1

var a =1;

</script>

<script>

// JavaScript代碼塊2

function f(){

    alert(1);

}

</script>

JavaScript解釋器在執(zhí)行腳本時,是按塊來執(zhí)行的。通俗地說,就是瀏覽器在解析HTML文檔流時,如果遇到一個<script>標簽,則JavaScript解釋器會等到這個代碼塊都加載完后,先對代碼塊進行預編譯,然后再執(zhí)行。執(zhí)行完畢后,瀏覽器會繼續(xù)解析下面的HTML文檔流,同時JavaScript解釋器也準備好處理下一個代碼塊。

由于JavaScript是按塊執(zhí)行的,所以如果在一個JavaScript塊中調用后面塊中聲明的變量或函數(shù)就會提示語法錯誤。例如,當JavaScript解釋器執(zhí)行下面代碼時就會提示語法錯誤,顯示變量a未定義,對象f找不到。

復制代碼 代碼如下:

<script>

// JavaScript代碼塊1

alert(a);

f();

</script>

<script>

// JavaScript代碼塊2

var a =1;

function f(){

    alert(1);

}

</script>

雖然說,JavaScript是按塊執(zhí)行的,但是不同塊都屬于同一個全局作用域,也就是說,塊之間的變量和函數(shù)是可以共享的。

1.4  借助事件機制改變JavaScript執(zhí)行順序

由于JavaScript是按塊處理代碼,同時又遵循HTML文檔流的解析順序,所以在上面示例中會看到這樣的語法錯誤。但是當文檔流加載完畢,如果再次訪問就不會出現(xiàn)這樣的錯誤。例如,把訪問第2塊代碼中的變量和函數(shù)的代碼放在頁面初始化事件函數(shù)中,就不會出現(xiàn)語法錯誤了。

復制代碼 代碼如下:

<script>

// JavaScript代碼塊1

window.onload = function(){        // 頁面初始化事件處理函數(shù)

    alert(a);

    f();

}

</script>

<script>

// JavaScript代碼塊2

var a =1;

function f(){

    alert(1);

}

</script>

為了安全起見,我們一般在頁面初始化完畢之后才允許JavaScript代碼執(zhí)行,這樣可以避免網(wǎng)速對JavaScript執(zhí)行的影響,同時也避開了HTML文檔流對于JavaScript執(zhí)行的限制。

注意

如果在一個頁面中存在多個windows.onload事件處理函數(shù),則只有最后一個才是有效的,為了解決這個問題,可以把所有腳本或調用函數(shù)都放在同一個onload事件處理函數(shù)中,例如:

復制代碼 代碼如下:

window.onload = function(){

    f1();

    f2();

    f3();

}

而且通過這種方式可以改變函數(shù)的執(zhí)行順序,方法是:簡單地調整onload事件處理函數(shù)中調用函數(shù)的排列順序。

除了頁面初始化事件外,我們還可以通過各種交互事件來改變JavaScript代碼的執(zhí)行順序,如鼠標事件、鍵盤事件及時鐘觸發(fā)器等方法,詳細講解請參閱第14章的內容。

1.5  JavaScript輸出腳本的執(zhí)行順序

在JavaScript開發(fā)中,經(jīng)常會使用document對象的write()方法輸出JavaScript腳本。那么這些動態(tài)輸出的腳本是如何執(zhí)行的呢?例如:

復制代碼 代碼如下:

document.write('<script type="text/javascript">');

document.write('f();');

document.write('function f(){');

document.write('alert(1);');

document.write('}');

document.write('</script>');


運行上面代碼,我們會發(fā)現(xiàn):document.write()方法先把輸出的腳本字符串寫入到腳本所在的文檔位置,瀏覽器在解析完document.write()所在文檔內容后,繼續(xù)解析document.write()輸出的內容,然后才按順序解析后面的HTML文檔。也就是說,JavaScript腳本輸出的代碼字符串會在輸出后馬上被執(zhí)行。

請注意,使用document.write()方法輸出的JavaScript腳本字符串必須放在同時被輸出的<script>標簽中,否則JavaScript解釋器因為不能夠識別這些合法的JavaScript代碼,而作為普通的字符串顯示在頁面文檔中。例如,下面的代碼就會把JavaScript代碼顯示出來,而不是執(zhí)行它。

復制代碼 代碼如下:

document.write('f();');

document.write('function f(){');

document.write('alert(1);');

document.write(');');

但是,通過document.write()方法輸出腳本并執(zhí)行也存在一定的風險,因為不同JavaScript引擎對其執(zhí)行順序不同,同時不同瀏覽器在解析時也會出現(xiàn)Bug。

Ø 問題一,找不到通過document.write()方法導入的外部JavaScript文件中聲明的變量或函數(shù)。例如,看下面示例代碼。

復制代碼 代碼如下:

document.write('<script type="text/javascript" src="http://www.fzitv.net/test.js">

</script>');

document.write('<script type="text/javascript">');

document.write('alert(n);');  // IE提示找不到變量n

document.write('</script>');

alert(n+1);                          // 所有瀏覽器都會提示找不到變量n

外部JavaScript文件(test.js)的代碼如下:

復制代碼 代碼如下:

var n = 1;

分別在不同瀏覽器中進行測試,會發(fā)現(xiàn)提示語法錯誤,找不到變量n。也就是說,如果在JavaScript代碼塊中訪問本代碼塊中使用document.write()方法輸出的腳本中導入的外部JavaScript文件所包含的變量,會顯示語法錯誤。同時,如果在IE瀏覽器中,不僅在腳本中,而且在輸出的腳本中也會提示找不到輸出的導入外部JavaScript文件的變量(表述有點長和繞,不懂的讀者可以嘗試運行上面代碼即可明白)。

Ø 問題二,不同JavaScript引擎對輸出的外部導入腳本的執(zhí)行順序略有不同。例如,看下面示例代碼。

復制代碼 代碼如下:

<script type="text/javascript">

document.write('<script type="text/javascript" src="http://shaozhuqing.com/test1.js">

</script>');

document.write('<script type="text/javascript">');

document.write('alert(2);')

document.write('alert(n+2);');

document.write('</script>');

</script>

<script type="text/javascript">

alert(n+3);

</script>


外部JavaScript文件(test1.js)的代碼如下所示。
復制代碼 代碼如下:

var n = 1;

alert(n);

在IE瀏覽器中的執(zhí)行順序如圖1-6所示。

圖1-6  IE 7瀏覽器的執(zhí)行順序和提示的語法錯誤

在符合DOM標準的瀏覽器中的執(zhí)行順序與IE瀏覽器不同,且沒有語法錯誤,如圖1-7所示的是在Firefox 3.0瀏覽器中的執(zhí)行順序。

圖1-7  Firefox 3瀏覽器的執(zhí)行順序和提示的語法錯誤

解決不同瀏覽器存在的不同執(zhí)行順序,以及可能存在Bug。我們可以把凡是使用輸出腳本導入的外部文件,都放在獨立的代碼塊中,這樣根據(jù)上面介紹的JavaScript代碼塊執(zhí)行順序,就可以避免這個問題。例如,針對上面示例,可以這樣設計:

復制代碼 代碼如下:

<script type="text/javascript">

document.write('<script type="text/javascript" src="http://www.fzitv.net/test1.js"></script>');

</script>

<script type="text/javascript">

document.write('<script type="text/javascript">');

document.write('alert(2);') ; // 提示2

document.write('alert(n+2);'); // 提示3

document.write('</script>');

alert(n+3); // 提示4

</script>

<script type="text/javascript">

alert(n+4); // 提示5

</script>

這樣在不同瀏覽器中都能夠按順序執(zhí)行上面代碼,且輸出順序都是1、2、3、4和5。存在問題的原因是:輸出導入的腳本與當前JavaScript代碼塊之間的矛盾。如果單獨輸出就不會發(fā)生沖突了。

相關文章

  • JavaScript之引用類型介紹

    JavaScript之引用類型介紹

    引用類型通常叫作類(class),也就是說,遇到引用值時,所處理的就是對象。
    2012-08-08
  • JavaScript CSS修改學習第三章 修改樣式表

    JavaScript CSS修改學習第三章 修改樣式表

    在這一章我打算通過直接修改頁面的樣式表而不是通過訪問元素的辦法來修改PRE的背景顏色。不幸的是,瀏覽器嚴重的不兼容性讓這個代碼基本上不能使用。
    2010-02-02
  • javascript彈出窗口 window.open使用方法以及參數(shù)說明分析篇

    javascript彈出窗口 window.open使用方法以及參數(shù)說明分析篇

    window.open是網(wǎng)頁中經(jīng)常遇到的彈出窗口代碼,不是網(wǎng)絡中比較反感的那類彈出代碼。用于新頁面?zhèn)髦?,回傳等?/div> 2009-12-12
  • 微信小程序wx:for循環(huán)的實例詳解

    微信小程序wx:for循環(huán)的實例詳解

    在組件上使用 wx:for 控制屬性綁定一個數(shù)組,即可使用數(shù)組中各項的數(shù)據(jù)重復渲染該組件。這篇文章主要介紹了微信小程序wx:for循環(huán)的相關知識,需要的朋友可以參考下
    2018-10-10
  • 全選復選框JavaScript編寫小結(附代碼)

    全選復選框JavaScript編寫小結(附代碼)

    這篇文章主要介紹了全選”復選框JavaScript編寫,分別附上html和js代碼以供大家更深刻了解,具體操作步驟大家可查看下文的詳細講解,感興趣的小伙伴們可以參考一下。
    2017-08-08
  • javascript中hasOwnProperty() 方法使用指南

    javascript中hasOwnProperty() 方法使用指南

    這篇文章主要詳細介紹了javascript中hasOwnProperty() 方法使用指南,非常的全面,推薦給有需要的小伙伴參考下。
    2015-03-03
  • JavaScript 詳解緩動動畫的封裝與使用

    JavaScript 詳解緩動動畫的封裝與使用

    緩動動畫原理:移動的像素慢慢減少,讓效果看起來更柔和更美觀,通過定時器加回調函數(shù),實現(xiàn)動畫效果以及更多具體功能,非常好用
    2021-11-11
  • JavaScript關鍵字this的用法總結

    JavaScript關鍵字this的用法總結

    這篇文章介紹了JavaScript關鍵字this的用法,文中通過示例代碼介紹的非常詳細。對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-06-06
  • JavaScript中各數(shù)制轉換全面總結

    JavaScript中各數(shù)制轉換全面總結

    這篇文章主要介紹了JavaScript中各數(shù)制轉換,利用toString的基模式來進行轉換,對數(shù)字調用 toString(10) 與調用 toString() 它們返回的區(qū)別和相同之處等等都在本文中提及,具體操作步驟大家可查看下文的詳細講解,感興趣的小伙伴們可以參考一下。
    2017-08-08
  • 基于dom編程中 動態(tài)創(chuàng)建與刪除元素的使用

    基于dom編程中 動態(tài)創(chuàng)建與刪除元素的使用

    本篇文章小編將為大家介紹,基于dom編程中動態(tài)創(chuàng)建與刪除元素的使用,有需要的朋友可以參考一下
    2013-04-04

最新評論

桦甸市| 鄂托克前旗| 德安县| 临高县| 肥城市| 若羌县| 广东省| 和硕县| 保定市| 麟游县| 金坛市| 固始县| 扶沟县| 宁强县| 金塔县| 慈溪市| 永州市| 石屏县| 民和| 铜山县| 铁岭市| 牙克石市| 肇州县| 克什克腾旗| 湄潭县| 建水县| 江安县| 连州市| 象州县| 湾仔区| 靖州| 锡林浩特市| 大石桥市| 平谷区| 重庆市| 全南县| 威宁| 沐川县| 新干县| 兰西县| 美姑县|