一個討論引發關於js中函數聲明,函數表達式,形參與變量聲明賦值引發的一些事


這篇文章寫的是關於一個討論的一些東西,算是整理和學習!。討論來源一個強大的前端群,群主 司徒正美(博客: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下就會提前塊級作用域中的函數聲明,而且后面的聲明會覆蓋前面的聲明。

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM