在定義一個函數的時候一般有兩種聲明方式:javascript
foo(){}; // 函數聲明 var foo = function(){}; // 函數表達式
讓咱們先看一個例子:css
foo(); // 函數聲明 foo_later(); // foo_later is not a function function foo(){ console.log('函數聲明'); } var foo_later = function(){ console.log('函數表達式'); }
能夠看到,函數聲明foo被預解析了,它能夠在其自身代碼以前執行;而函數表達式foo_later則不能。要解決這個問題,咱們先要弄清楚JavaScript解析器的工做機制。java
JavaScript解析器會在自身做用域內將變量和函數聲明提早(hoist),也就是說,上面的例子其實被解析器理解解析成了如下形式:express
function foo(){ console.log('函數聲明'); } // 函數聲明所有被提早 var foo_later; // 函數表達式(變量聲明)僅將變量提早,賦值操做沒有被提早 foo(); foo_later(); foo_later = function(){ console.log('函數表達式'); }
這樣也就能夠解釋,爲何在函數表達式以前調用函數,會返回錯誤了,由於它尚未被賦值,只是一個未定義變量,固然沒法被執行。函數
一樣的,咱們也能夠試着猜想下面這段代碼的輸出結果:spa
console.log(declaredLater); var declaredLater = "Now it's defined!"; console.log(declaredLater);
該段代碼能夠被解析成一下形式:code
var declaredLater; console.log(declaredLater); // undefined declaredLater = "Now it's defined!"; console.log(declaredLater); // Now it's defined!
變量聲明被提到最前(因此不會報出變量不存在的錯誤),但賦值沒有被提早,因此第一次的輸出結果是undefined。blog
因爲函數聲明會被預解析,因此不要使用此種方法來聲明不一樣函數。嘗試猜測下面例子的輸出結果:ip
if(true){ function aaa(){ alert('1'); } } else{ function aaa(){ alert('2'); } } aaa();
與咱們預想的不一樣,該段代碼彈出的是「2」.這是由於兩個函數聲明在if語句被執行以前就被預解析了,因此if語句根本沒有用,調用aaa()的時候直接執行了下面的函數。作用域
經過上面的講解能夠總結以下:
經過練習上面的實例本身多感覺一下。另外,做爲最佳實踐:變量聲明必定要放在做用域/函數的最上方(JavaScript 只有函數做用域!)。
參考: