javascript運(yùn)行機(jī)制之執(zhí)行順序理解
JavaScript是一種描述型腳本語(yǔ)言,它不同于java或C#等編譯性語(yǔ)言,它不需要進(jìn)行編譯成中間語(yǔ)言,而是由瀏覽器進(jìn)行動(dòng)態(tài)地解析與執(zhí)行。如果你不能理解javaScript語(yǔ)言的運(yùn)行機(jī)制,或者簡(jiǎn)單地說(shuō),你不能掌握javascript的執(zhí)行順序,那你就猶如伯樂(lè)駕馭不了千里馬,讓千里馬脫韁而出,四處亂竄。
那么JavaScript是怎么來(lái)進(jìn)行解析的嗎?它的執(zhí)行順序又是如何的呢?在了解這些之前,我們先來(lái)認(rèn)識(shí)幾個(gè)重要的術(shù)語(yǔ):
1、代碼塊
JavaScript中的代碼塊是指由<script>標(biāo)簽分割的代碼段。例如:
<script type="text/javascript"> alert("這是代碼塊一"); </script> <script type="text/javascript"> alert("這是代碼塊二"); </script>
JS是按照代碼塊來(lái)進(jìn)行編譯和執(zhí)行的,代碼塊間相互獨(dú)立,但變量和方法共享。什么意思呢? 舉個(gè)例子,你就明白了:
<script type="text/javascript"> alert(str);//因?yàn)闆](méi)有定義str,所以瀏覽器會(huì)出錯(cuò),下面的不能運(yùn)行 alert("我是代碼塊一");//沒(méi)有運(yùn)行到這里 var test = "我是代碼塊一變量"; </script> <script type="text/javascript"> alert("我是代碼塊二"); //這里有運(yùn)行到 alert(test); //彈出"我是代碼塊一變量" </script>
上面的代碼中代碼塊一中運(yùn)行報(bào)錯(cuò),但不影響代碼塊二的執(zhí)行,這就是代碼塊間的獨(dú)立性,而代碼塊二中能調(diào)用到代碼一中的變量,則是塊間共享性。
2、聲明式函數(shù)與賦值式函數(shù)
JS中的函數(shù)定義分為兩種:聲明式函數(shù)與賦值式函數(shù)。
<script type="text/javascript"> function Fn(){ //聲明式函數(shù) } var Fn = function{ //賦值式函數(shù) } </script>
聲明式函數(shù)與賦值式函數(shù)的區(qū)別在于:在JS的預(yù)編譯期,聲明式函數(shù)將會(huì)先被提取出來(lái),然后才按順序執(zhí)行js代碼。
3、預(yù)編譯期與執(zhí)行期
事實(shí)上,JS的解析過(guò)程分為兩個(gè)階段:預(yù)編譯期(預(yù)處理)與執(zhí)行期。
預(yù)編譯期JS會(huì)對(duì)本代碼塊中的所有聲明的變量和函數(shù)進(jìn)行處理(類似與C語(yǔ)言的編譯),但需要注意的是此時(shí)處理函數(shù)的只是聲明式函數(shù),而且變量也只是進(jìn)行了聲明但未進(jìn)行初始化以及賦值。
<script type="text/javascript"> Fn(); //執(zhí)行結(jié)果:"執(zhí)行了函數(shù)2",同名函數(shù)后者會(huì)覆蓋前者 function Fn(){ //函數(shù)1 alert("執(zhí)行了函數(shù)1"); } function Fn(){ //函數(shù)2 alert("執(zhí)行了函數(shù)2"); } </script>
<script type="text/javascript"> Fn(); //執(zhí)行結(jié)果:"執(zhí)行了聲明式函數(shù)",在預(yù)編譯期聲明函數(shù)及被處理了,所以即使Fn()調(diào)用函數(shù)放在聲明函數(shù)前也能執(zhí)行。 function Fn(){ //聲明式函數(shù) alert("執(zhí)行了聲明式函數(shù)"); } var Fn = function(){ //賦值式函數(shù) alert("執(zhí)行了賦值式函數(shù)"); } </script>
//代碼塊一 <script type="text/javascript"> alert(str);//瀏覽器報(bào)錯(cuò),但并沒(méi)有彈出信息窗 </script> //代碼塊二 <script type="text/javascript"> alert(str); //彈窗"undefined" var str = "aaa"; </script> //js在預(yù)處理期對(duì)變量進(jìn)行了聲明處理,但是并沒(méi)有進(jìn)行初始化與賦值,所以導(dǎo)致代碼塊二中的變量是unfiened的,而代碼一中的變量是完全不存在的,所以瀏覽器報(bào)錯(cuò)。
理解了上面的幾個(gè)術(shù)語(yǔ),相信大家對(duì)JS的運(yùn)行機(jī)制已經(jīng)有了個(gè)大概的印象了,現(xiàn)在我們來(lái)看個(gè)例子:
<script type="text/javascript"> Fn(); //瀏覽器報(bào)錯(cuò):"undefined" </script> <script type="text/javascript"> function Fn(){ //函數(shù)1 alert("執(zhí)行了函數(shù)1"); } </script>
為什么運(yùn)行上面的代碼瀏覽器會(huì)報(bào)錯(cuò)呢?聲明函數(shù)不是會(huì)在預(yù)處理期就會(huì)被處理了嗎,怎么還會(huì)找不到Fn()函數(shù)呢?其實(shí)這是一個(gè)理解誤點(diǎn),我們上面說(shuō)了JS引擎是按照代碼塊來(lái)順序執(zhí)行的,其實(shí)完整的說(shuō)應(yīng)該是按照代碼塊來(lái)進(jìn)行預(yù)處理和執(zhí)行的,也就是說(shuō)預(yù)處理的只是執(zhí)行到的代碼塊的聲明函數(shù)和變量,而對(duì)于還未加載的代碼塊,是沒(méi)法進(jìn)行預(yù)處理的,這也是邊編譯邊處理的核心所在。
現(xiàn)在,讓我們來(lái)總結(jié)整理下:
step 1. 讀入第一個(gè)代碼塊。
step 2. 做語(yǔ)法分析,有錯(cuò)則報(bào)語(yǔ)法錯(cuò)誤(比如括號(hào)不匹配等),并跳轉(zhuǎn)到step5。
step 3. 對(duì)var變量和function定義做“預(yù)編譯處理”(永遠(yuǎn)不會(huì)報(bào)錯(cuò)的,因?yàn)橹唤馕稣_的聲明)。
step 4. 執(zhí)行代碼段,有錯(cuò)則報(bào)錯(cuò)(比如變量未定義)。
step 5. 如果還有下一個(gè)代碼段,則讀入下一個(gè)代碼段,重復(fù)step2。
step6. 結(jié)束。
而根據(jù)HTML文檔流的執(zhí)行順序,需要在頁(yè)面元素渲染前執(zhí)行的js代碼應(yīng)該放在<body>前面的<script>代碼塊中,而需要在頁(yè)面元素加載完后的js放在</body>元素后面,body標(biāo)簽的onload事件是在最后執(zhí)行的。
<script type="text/javascript"> alert("first"); function Fn(){ alert("third"); } </script> <body οnlοad="Fn()"> </body> <script type="text/javascript"> alert("second"); </script>
到此這篇關(guān)于javascript運(yùn)行機(jī)制之執(zhí)行順序理解的文章就介紹到這了,更多相關(guān)javascript運(yùn)行機(jī)制之執(zhí)行順序內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
JavaScript實(shí)現(xiàn)父子dom同時(shí)綁定兩個(gè)點(diǎn)擊事件,一個(gè)用捕獲,一個(gè)用冒泡時(shí)執(zhí)行順序的方法
這篇文章主要介紹了JavaScript實(shí)現(xiàn)父子dom同時(shí)綁定兩個(gè)點(diǎn)擊事件,一個(gè)用捕獲,一個(gè)用冒泡時(shí)執(zhí)行順序的方法,涉及javascript事件的觸發(fā)與執(zhí)行原理及相關(guān)操作技巧,需要的朋友可以參考下2017-03-03實(shí)例講解JavaScript中call、apply、bind方法的異同
這篇文章主要以實(shí)例講解的方式為大家總結(jié)了JavaScript中call、apply、bind方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-09-09layui問(wèn)題之渲染數(shù)據(jù)表格時(shí),僅出現(xiàn)10條數(shù)據(jù)的解決方法
今天小編就為大家分享一篇layui問(wèn)題之渲染數(shù)據(jù)表格時(shí),僅出現(xiàn)10條數(shù)據(jù)的解決方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-09-09詳解JavaScript節(jié)流函數(shù)中的Throttle
函數(shù)節(jié)流,就是對(duì)會(huì)頻繁觸發(fā)的函數(shù)事件做一些限制,讓這些函數(shù)可以在每隔一定的時(shí)間或者每次滿足一定的條件下再觸發(fā)。一般我們會(huì)給他起一個(gè)名字throttle。也就是節(jié)流的意思。一般這樣的函數(shù)有 resize事件、ontouchmove事件等。2016-07-07高性能JavaScript循環(huán)語(yǔ)句和條件語(yǔ)句
這篇文章主要為大家介紹了高性能JavaScript循環(huán)語(yǔ)句和條件語(yǔ)句,感興趣的小伙伴們可以參考一下2016-01-01JS實(shí)現(xiàn)二維數(shù)組橫縱列轉(zhuǎn)置的方法
下面小編就為大家分享一篇JS實(shí)現(xiàn)二維數(shù)組橫縱列轉(zhuǎn)置的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-04-04分享一個(gè)插件實(shí)現(xiàn)水珠自動(dòng)下落效果
本篇文章給大家分享一個(gè)插件制作水珠自動(dòng)下落效果,效果非常逼真,感興趣的朋友可以添加下面代碼運(yùn)行看看效果哦2016-06-06JavaScript中三個(gè)等號(hào)和兩個(gè)等號(hào)的區(qū)別(== 和 ===)淺析
javascript中比較運(yùn)算符'=='與'==='可能大家用的比較多,但是大家對(duì)他的區(qū)別不是很清楚,接下來(lái)小編給大家介紹下js中三個(gè)等號(hào)和兩個(gè)等號(hào)的區(qū)別(== 和 ===),感興趣的朋友可以參考下2016-09-09微信小程序?qū)崿F(xiàn)客服功能(客服消息)的全過(guò)程
在最近做的微信小程序中需要實(shí)現(xiàn)一個(gè)自帶的客服功能,下面這篇文章主要給大家介紹了關(guān)于微信小程序?qū)崿F(xiàn)客服功能(客服消息)的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-12-12