最近在複習javascript的事件處理時發現了一個問題,而後也是我來寫javascript的預編譯和執行順序的問題javascript
代碼:html
代碼一
<html> <head> <title>事件處理</title> <meta http-equiv="content-type" content="text/html;charset=utf-8"/> <script type='text/javascript'> //頁面在在完成加載後 window.onload=function(){ var input=document.getElementById('button'); var p=document.getElementById('p'); var i=1; while(input){ input.onclick=function(){ p.innerHTML+='<br />('+ i +') '+this.nodeName; } i++; input=input.parentNode; } } </script> </head> <body> <div> <input type='button' value='Event事件' id='button' /> <p id='p'>事件捕獲的順序:</p> </div> </body> </html>
顯示的結果爲:java
當我更改了代碼中紅色的部分後獲得的結果又不相同:node
代碼二
<html> <head> <title>事件處理</title> <meta http-equiv="content-type" content="text/html;charset=utf-8"/> <script type='text/javascript'> //頁面在在完成加載後 window.onload=function(){ var input=document.getElementById('button'); var p=document.getElementById('p'); var i=1; while(input){ input.onclick=function(){ p.innerHTML+='<br />('+ i++ +') '+this.nodeName; } input=input.parentNode; } } </script> </head> <body> <div> <input type='button' value='Event事件' id='button' /> <p id='p'>事件捕獲的順序:</p> </div> </body> </html>
獲得的結果爲:函數
得出這兩種不一樣的結果那是由於javascript代碼在運行時有預編譯和執行兩個階段,在預編譯階段會對函數和變量進行處理,對全部的聲明變量會賦值爲underfined,對全部的聲明函數也會賦值爲函數的定義。測試
下面咱們來測試javascript的執行過程ui
1.javascript代碼執行順序時按照腳本標籤<script>出現的順序來肯定的,瀏覽下面頁面你會發現代碼是按從上到下的順序執行的this
<script type='text/javascript'> alert('one'); </script> <script type='text/javascript'> alert('two'); </script> <script type='text/javascript'> alert('three'); </script>
2. 由於變量在預編譯時被賦予一個undefined初值,因此下面代碼中,第一個變量name在代碼中沒有被賦值,全部就延用undefined這個值,下面的name被賦予了Jude,因此第二次輸出的是Jude這個字符。spa
<script type='text/javascript'> alert(name); //顯示undefined var name='Jude'; alert(name); //顯示Jude </script>
3.從以下結果中咱們知道先是連續兩次輸出Hello Wrold!,最後連續兩次輸出test,得出這樣的結果是由於javascript並不是是徹底按照順序執行的,而是在執行以前先進行一個預編譯,預編譯時聲明式函數被提取出來,優先執行,並且相同的函數會進行覆蓋,再執行賦值式函數。code
<script type='text/javascript'> test(); //輸出Hello World! function test(){ alert('hello'); //聲明式函數 } test(); //輸出Hello World! var test=function(){ //賦值式函數 alert('test'); } test(); //輸出test function test(){ //聲明式函數 alert('Hello World!'); } test(); //輸出test </script>
4.下面代碼顯示顯示hello,再顯示hello world!,這是由於javascript中的給個代碼塊是相互獨立的,當腳本遇到第一個<script>標籤時,則javascript解析器會等這個代碼塊加載完成後,先對它進行預編譯,而後再執行之,而後javascript解析器準備解析下一個代碼塊,因爲javascript是按塊執行的,全部一個javascript調用下一個塊的函數或者變量時,會出現錯誤
<script type='text/javascript'> function test(){ alert('hello'); //顯示hello } test() </script> <script type='text/javascript'> function test(){ alert('hello world!'); //顯示hello world! } test() </script>
5.雖然javascript是按塊執行的,但不一樣的塊卻屬於相同的全局做用域,不一樣的塊的變量和函數式能夠相互使用的,也就是某個塊能夠使用前面塊的變量和函數,卻不能夠使用它以後的塊的變量和函數
<script type='text/javascript'> alert(name); //顯示undefined var name='Jude'; function test(){ alert('hello'); } fun(); //不能調用下一個塊的函數 </script> <script type='text/javascript'> alert(name); //能夠調用上一個塊的變量,顯示Jude test(); //能夠調用上一個塊的函數,顯示hello function fun(){ alert('fun'); } </script>
6.javascript在預編譯階段是以函數來劃分做用域的,而後再經過var 聲明的變量來與聲明函數開闢內存空間,對var變量賦初值undefined。在執行階段再根據做用域來嘴變量進行賦值.
第一個代碼塊中函數裏面的變量a是局部變量,由於a在函數內從新用var定義,因此輸出undefined,而變量b是全局變量,由於在函數內沒有用var從新聲明b,因此在給變量b賦值時到全局變量中找全局變量b的值,因此輸出的是b.
第二個代碼塊中的函數內都從新聲明瞭變量a和b,因此他們都是函數內的局部變量,因此都輸出undefined。
<script type='text/javascript'> var a='a'; var b='b'; function test(){ alert(a); //顯示undefined alert(b); //顯示b var a='test'; } test(); </script> <script type='text/javascript'> var a='a'; var b='b'; function test(){ alert(a); //顯示undefined alert(b); //顯示undefined var a='test'; var b='test'; } test(); </script>
綜上所述,javascript在執行時的步驟是:
一、先讀入第一段代碼塊
二、對代碼塊進行語法分析,若是出現語法錯誤,直接執行第5步驟
三、對var變量和function定義的函數進行「預編譯處理」(賦值式函數是不會進行預編譯處理的)
四、執行代碼塊,有錯則報錯
五、若是還有下一段代碼塊,則讀入下一段代碼塊,重複步驟2
六、結束