這篇文章寫的是關於一個討論的一些東西,算是整理和學習!。討論來源一個強大的前端群,群主 司徒正美(博客:http://www.cnblogs.com/rubylouvre/ 微博:http://weibo.com/jslouvre?topnav=1&wvr=5&topsug=1)發了這樣一個代碼片段:

先說說我自己第一反應的答案吧:
1 function a(){} 2 undefined 3 [1,2,3] 4 ee 5 444 6 6
先說說我自己一開始最基本的理解吧:
在函數中變量的聲明會被提前,但賦值會到代碼所在行才會進行,另外函數名只是一個指針而不是綁定的,是可以修改的,因為函數本身就是一個對象(可以參考:http://www.cnblogs.com/zhouyongtao/archive/2012/11/19/2776776.html)。
a,aa變量的聲明被提到代碼的最前面此時值為undefined,但接着a指向了一個函數,故console.log(a)輸出為function a(){},而console.log(aa)輸出undefined,console.log(arguments)輸出就為:[1,2,3]。
然后a,aa,arguments均被賦值,故console.log(a)輸出為:ee,console.log(aa)輸出為:444,console.log(arguments)輸出為:6。
事情到這就真的完了嗎?事實上遠遠沒有完。
有人說:“這里面參數的優先級低於變量聲明和函數聲明,所以一直被派上用處”。還有人說:“知識點:函數,形參,變量同名的話,通俗理解,函數>形參>變量”。
那么函數聲明,變量聲明,賦值,如果有同名情況出現和這幾者之間到底是誰優先呢?或者說誰覆蓋誰?
后來大佬又發話了。

看完不能很好的理解,感覺抽象了。后來又有人貼出這樣一篇正妹的文章:http://chauvetxiao.com/bo-blog/read.php?1
其中有幾個demo很不錯,引用過來理解和驗證一下大佬所說的東西還是特別有幫助的。(下面的demo大多數出自於正妹的文章)
fu();//2 var fu=function(){ console.log(1); }; function fu(){ console.log(2); } fn();//1
這個demo和上面那個例子驗證了大佬的第一句話“變量聲明,當變量聲明遇到VO中已經有同名的時候,不會影響已經存在的屬性”。
第二句和第三句就不解釋了。因為從上面第一例子已經看得出來了。
但第四句后半句覺得不是很對。疑問來源於這樣的兩個demo
1 function a(){ 2 console.log('2'); 3 } 4 var a; 5 console.log(a);//function a(){console.log('2);}
1 function a(){ 2 console.log(a); 3 var a=2; 4 } 5 a();//undefined
那么在函數內部和全局環境中,是誰覆蓋誰?其實第一個例子中,聲明與變量聲明是先后進行,而第二例子中是函數聲明先進行,調用函數函數時再有變量的聲明。所以前者輸出的正如大佬所說是function a(){consoleo.log('2')},后者是undefined。
另外也發現一點東西,js中全局變量的聲明並不會提前。斷點調試就能發現在window對象並沒有這樣一個屬性。
1 console.log(num);//錯誤 2 num=2;
這樣的話,這個例子也比較容易弄懂。
1 var num1 = 1; 2 3 function fn(num3){ 4 5 console.log(num1); //output undefined 6 7 console.log(num3); //output 4 8 9 console.log(num4); //throw error “num4 is not defined” 10 11 console.log(num2); //throw error “num2 is not defined” 12 13 var num1 = num4 = 2; 14 15 num2 = 3; 16 17 var num3= 5; 18 19 } 20 21 fn(4);
如果理解了上面的東西,這樣的demo也很容易搞懂了。
1 function fn(t){ 2 3 t(); 4 5 function t(){ 6 7 console.log(2); 8 9 } 10 11 var t = function(){ 12 13 console.log(3); 14 15 } 16 17 } 18 19 fn(function(){console.log(1)}); //output 2
另外也學到一個東西,對於塊級作用中的函數聲明在chrome和ie下會提前,而在firefox中,招待時才會進行。
1 console.log(fn.toString()); 2 3 if (true) { 4 5 function fn(){ return 1; } 6 7 }else { 8 9 if(false){ 10 11 function fn(){ return 2; } 12 13 } 14 15 }
chrome和Ie下輸出function fn(){return 2;}
而firefox中拋出異常。
如果不是很懂,再看這個例子。
1 if (true) { 2 3 function fn(){ return 1; } 4 5 }else { 6 7 if(false){ 8 9 function fn(){ return 2; } 10 11 } 12 13 } 14 15 console.log(fn.toString());
chrome和ie一均為function fn(){ return 2;},而firefox中依然報錯。
可見三者處理並不相同。ff中會提前變量的聲明,但不會提前塊級作用域中的函數聲明。而chrome和ie下就會提前塊級作用域中的函數聲明,而且后面的聲明會覆蓋前面的聲明。
