一、js運行三部曲:
1.語法分析(通篇掃描看有沒有語法錯誤)
2.預編譯
3.解釋執行
二、預編譯前奏
1、imply global 暗示全局變量:任何變量如果未經聲明就賦值,此變量為全局對象所有
eg: a = 123;
var a = b =123;
2、一切聲明的全局變量,全是window的屬性,一切定義在全局上的變量,都歸window所有(window等價於全局)
eg: console.log(a) 等價於 console.log(window.a);
舉個例子:
<script> function test(){ var a = b = 123; } test(); console.log(b); </script>
其結果為:123
如果將console.log(b) 改成 console.log(a) 則會出現 “
” 的錯誤。這是因為執行test()函數時,先對 b賦值,使 b=123, 然后再 var a 進行聲明, 最后使a=b,
b在未聲明的時候進行賦值,所以為全局變量,可以在函數外訪問,而a則是局部變量,不能再函數外訪問
三、預編譯的兩個規則:
a.函數聲明整體提升 : 函數聲明不管位於哪里,系統總會把聲明提升到邏輯的最前面,因此無論函數調用在聲明前或聲明后結果都一樣
b.變量 聲明提升:會把變量的聲明提升到函數調用前面
舉兩個小例子:
<script>
test();
functiont test(){
console.log('a');
}
</script>
輸出的結果為: a
<script> console.log(a); var a = 123; </script>
輸出結果為:undefined;
四、預編譯四部曲(函數預編譯時)
通過下面例子進行講解
<script type="text/javascript"> function fn(a) { console.log(a); var a = 123; console.log(a); function a() {} console.log(a); var b = function() {} console.log(b); function d() {} } fn(1);
1.創建AO對象 (Activation object)(執行期上下文)
AO{ }
2:找形參和變量聲明,將變量和形參名作為AO()屬性名,值為undefined
AO{
a:undefined
b:undefined
}
3.將實參值和形參值統一
AO{
a:1
b:undefined
}
4.在函數體里找函數聲明,值賦予函數體
AO{
a:function a(){}
b:undefined
d:function d(){}
}
預編譯完后進行執行:
首先一句一句執行,執行第一句console.log(a);那么,會在AO對象中調取a,在AO對象中a等於function a(){},那么就輸出function a(){}
然后到達第二句 var a = 123,var a 已經被提升了,所以不用管,直接到a = 123,所以,在AO對象中,a變成了123
AO對象變成123后,再來進行執行第三句,console.log(a);那么,現在a等於123,那么就是輸出123,
到達第四句,第四句是函數,由於函數已經被提升了,所以沒有這一步,然后再到第五句,第五句是console.(a),所以輸出還是123吧
然后再到第六句,第六句是var b = function (){},所以就要把在AO對象中的b的屬性改為function(){}
所以在第七句b的輸出就是function(){},第八句直接被提升了,所以不用讀了。
結果為:
function a(){}
123
123
function (){}
全局預編譯:
生成一個GO global object對象(等價於window)
例:
<script> global = 100; function fn(){ console.log(global); global=200; console.log(global); var global=300; } fn(); var global; </script>
結果為:
undefined
200
執行過程:首先生成GO{
global:undefined
}
執行第一行:global = 100
執行fn()時生成AO{
global = undefined;
}
注意
js不是全文編譯完成再執行,而是塊編譯,即一個script塊中預編譯然后執行,再按順序預編譯下一個script塊再執行
但是此時上一個script快中的數據都是可用的了,而下一個塊中的函數和變量則是不可用的。