JavaScript:詞法分析、連續賦值猜想 原創文章,轉摘請註明出處:蘇福:http://www.cnblogs.com/susufufu/p/5851642.html 深夜發文,先吐槽下博客園的編輯器,真不方便!我都是本地編輯好了在粘過來的,要是不用MarkDown寫的話,那每次都得改改改啊! ...
JavaScript:詞法分析、連續賦值猜想
原創文章,轉摘請註明出處:蘇福:http://www.cnblogs.com/susufufu/p/5851642.html
深夜發文,先吐槽下博客園的編輯器,真不方便!我都是本地編輯好了在粘過來的,要是不用MarkDown寫的話,那每次都得改改改啊!
先說下這個老話題:連續賦值
例1:
function a(){
var o1 = o2 = 5;
}
a();
console.log(o1);
console.log(o2);
結果是什麼?console.log(o1);這句簡單undefined,而console.log(o2);這句呢?答案是5,o2變成了全局變數了
這是實際執行順序:
var o1;
o2 = 5; //o2未使用var聲明,所以變全局變數了
o1 = o2;
例2:
var foo = {n:1};
var bar = foo;
foo.x = foo = {n:2};
console.log(foo.x);
console.log(bar.x);
很早以前的面試題目了,相信很多人知道答案,考點:詞法分析、執行順序、運算符優先順序等
這是我理解的實際執行順序:
var foo;
var bar;
foo = {n:1};
bar = foo; //bar = {n:1}
foo.x = undefined; //
foo.x = (foo = {n:2});
console.log(foo.x); //undefined
console.log(bar.x); //{ n: 2 }
我是這麼猜想的:自我感覺勉強說的通,有不對的地方請指出!
JS引擎遇foo.x = foo = {n:2}; 詞法分析為foo.x, =, foo, =, {n:2}
執行順序:
1. 先為foo添加x屬性,未賦值(undefined),這裡的foo還是{n:1}
2. 遇到第一個'=',準備為x賦值
3. '='優先順序最低,先計算右邊表達式的值
4. 執行foo = {n:1},並將結果賦值給x
最終foo的引用指向了{n:2}
而bar的引用沒變,始終指向原來的{n:1},而{n:1}被添加了x屬性{n:2}變為{n:1,x:{n:2}},這就是最後bar引用的值
下麵給大家介紹下JS的詞法分析,參考自《javascript權威指南》《你不知道的javascript》
JavaScript代碼自上而下執行,但是在js代碼執行前,會首先進行詞法分析,所以事實上,js運行要分為詞法分析和執行兩個階段。
詞法分析
詞法分析主要分為3步:
第1步:分析形參
第2步:分析變數聲明
第3步:分析函數聲明
如果存在函數嵌套,則從外往內進行詞法分析
具體步驟:
- 在函數執行的一瞬間,產生一個空的 Active Object(活動對象),下麵簡稱AO
- AO對象初始化
2.1 函數聲明的形參,形成AO的屬性,預設值是undefined,
2.2 接收實參,給剛剛形成AO的屬性的形參賦值 - var聲明、函數聲明均被提升到函數體頂部(若var聲明、函數聲明同名,則函數聲明將覆蓋變數聲明),註意,var聲明只提前了聲明部分,而函數聲明提前了整個函數定義。
- 分析var聲明變數!如 var age;(變數的值是在運行時期決定)
4.1 如果AO上沒有age屬性,則給AO添加age屬性,預設值是undefined
4.2 如果AO上有age屬性,則不做任何操作。 - 分析函數聲明!如 function foot(){}
51 如果AO上沒有foot屬性,則把函數賦給AO.foot屬性
5.2 如果AO上有foot屬性,則會直接覆蓋,把函數賦給AO.foot屬性(因為:若var聲明、函數聲明同名,則函數聲明將覆蓋變數聲明) - 依據此時AO的值,自上而下執行代碼
代碼演示與分析:
function a(b){
alert(b);
function b(){
alert(b);
}
b();
}
a(1);
這是個常見的面試題,如果不懂JavaScript的詞法分析,根本看不懂,下麵就按照JavaScript的詞法步驟進行分析,前面說過JavaScript自上而下執行,但是先進行詞法分析後執行代碼
分析過程:
- 形成活動對象AO={}
- 分析形參,--> AO={b:undefined}; 分析傳參,--> AO={b:1}
- 分析變數聲明var,沒有
- 分析函數聲明,AO.b=function(){alert(b);},執行覆蓋操作
執行過程:
alert(b);//function
b(); // 執行function b...alert(b),在函數b的作用域內部找不到b,根據作用域鏈原理往外層尋找,找到b就是函數自己,列印出function ...