在javascript中咱們定義函數有如下兩種方式:javascript
函數聲明java
function say(){ console.log('函數聲明'); }
函數表達式函數
var say = function(){ console.log('函數表達式'); }
在平時開發中,它們有着難以察覺的差異,咱們看下下面的例子:code
say(); var say = function(){ console.log('函數表達式'); } say(); function say(){ console.log('函數聲明'); } say();
能夠先在腦海中想一下答案,執行結果是:ip
函數聲明 函數表達式 函數表達式
來,咱們分析一下這個結果:作用域
1.第一次調用say函數時,函數還未被定義,那爲何能夠打印出「函數聲明」這個值呢?緣由在於開發
javascript解釋器中存在一種變量聲明被提高的機制,也就是說 函數聲明會被提高到做用域的最前面,即便寫代碼的時候是寫在最後面,也仍是會被提高至最前面。
而用函數表達式建立的函數是在運行時進行賦值,且要等到表達式賦值完成後才能調用
所以,即便函數還未被定義,可是函數聲明已經被提高到最前面了,上面那段代碼至關於:io
var say; //變量被提高,此時的值爲undefined say();// 函數被提高,輸出「函數聲明」 var say = function(){ console.log('函數表達式'); } say(); function say(){ console.log('函數聲明'); } say();
從下面兩個的對比,更能理解「函數聲明提高」這個概念:
1.console
var say; console.log(say); say(); function say(){ console.log('函數聲明'); } 輸出: f say(){ console.log('函數聲明'); } 函數聲明
2.function
var say; console.log(say); say(); var say = function(){ console.log('函數表達式'); } 輸出: undefined Uncaught TypeError: say is not a function at <anonymous>:3:1
2.第二次調用say函數時,咱們能夠先簡單理解爲此時的函數表達式
覆蓋了函數聲明
,所以輸出了‘函數表達式’,然而到了第三次調用say函數時,此時打印的居然仍是‘函數表達式’??爲何後面的函數聲明
沒有覆蓋前面的函數表達式
呢?其實在運行時因爲函數聲明提高的緣由,實際上運行的順序是相似於這樣的:
var say; //函數表達式中的var提早,值爲undefined function say() { console.log('函數聲明'); }//由於函數聲明提高,因此在最前面運行了 say(); //函數聲明 say = function() { //給say賦值函數 console.log('函數表達式'); } say();//函數表達式 say();//函數表達式
1.函數聲明在JS解析時進行函數提高,所以在同一個做用域內,無論函數聲明在哪裏定義,該函數均可以進行調用。2.函數表達式的值是在JS運行時肯定,而且在表達式賦值完成後,該函數才能調用