console.log(a); //Uncaught ReferenceError: a is not defined
因為沒有定義a所以報錯了。
var a = 52; console.log(a); //52
有定義a,並且給a賦值了52所以打印a就是52。
console.log(a); //undefined var a = 52;
雖然有定義a但是打印卻在變量a的前面,那為什么不是報錯而是打印出來的是undefined?因為在js執行代碼之前,js會先獲取到所有的變量並且把這些變量放置到js代碼的頂部。(簡稱變量聲明提前)
實際上,上面的代碼是這樣執行的:
var a; console.log(a);
所以代碼出來的就是undefined,那你是不是會疑問?我們給賦值給a的52到哪去了。雖然我前面說了js會事先獲取所有的變量並且將這些變量放置到頂部,但是變量的賦值並不會事先執行,也就是說,你在哪聲明的變量,這個變量的賦值就在哪執行。
var a; console.log(a); //undefined
雖然聲明了但沒有賦值所有undefined
console.log(a); function a(){ this.user = "追夢子"; }
為什么,可以事先就打印出函數a呢?因為函數的賦值在函數聲明的時候就已經賦值了,結合上面我說的變量提前,那是不是就可以理解這句話了?
當然這只是一種情況,還有一種情況,稍后說。
function a(){ this.user = "追夢子"; } console.log(a);
正常
a(); //Uncaught TypeError: a is not a function var a = function(){ console.log(52); }
為什么現在又不行了?因為現在的函數已經賦值給了變量a,現在它的執行過程和變量一樣了,我們通常把這種函數賦值給變量的形式叫做函數表達式。
var a = function(){ console.log(52); } a(); //52
正常
if(false){ var a = 1; } console.log(a); //undefined
之所以沒有報錯而是輸出了undefined是因為變量存在預解析的情況,又因為js沒有塊級作用域,所以最后代碼就成了這樣
var a; if(false){ a = 1; } console.log(a);
總結:
函數分為:函數聲明和函數表達式。
函數聲明--
function a(){ alert("追夢子博客"); }
函數表達式--
var a = function(){ alert("追夢子"); }
看似兩段相同的語句,它們的執行順序卻截然不同,函數聲明時的賦值行為是在函數創建的時候進行的,而函數表達式的賦值行為是在執行這句變量時進行的(因為它已經賦值給了變量所以我這里把它稱為變量)。
不管是變量還是函數都會存在變量聲明提前。
來看看幾題有意思的js例題,加以理解。
var a = 1; function b(){ console.log(a); //undefined var a = 5; } b();
為什么打印的是undefined?
我們先來看看它的解析過程:
var a = 1; function b(){ var a console.log(a); //undefined a = 5; } b();
變量提前了,那為什么不打印全局變量1呢?如果你有這個問題我猜你應該是JavaScript的新朋友,那我建議你看我的上一篇文章:
什么是作用域鏈,什么是原型鏈,它們的區別,在js中它們具體指什么?
在看完作用域鏈以后我相信你能夠看懂這個例子。
我們一起來看看另外一題比較有難度的js面試題:
var a = 1; function b() { a = 120; return; function a() {} } b(); alert(a); //1;
如果你看了上面一題我相信你應該有種不知所措的感覺,這里現在為什么又是1了呢?
我把執行過程的代碼寫出來我相信你就懂了。
var a = 1; function b() { var a; a = 120; return; function a() {} } b(); alert(a);
如果你正在js的進階階段肯定更悶了,你肯定會想我們不是寫return了嗎?return后面的代碼不是不執行嗎?為什么這里卻影響了這段代碼?
雖然return后面的代碼不會被執行,但是在js預解析的時候(變量提升的時候)還是會把return后面的變量提前,所以我們這段代碼因為變量提前所以函數里面的變量a就成了局部變量,因為函數外部是訪問不了函數內部的變量所以就輸出了1。
另外提兩點,函數的arguments和函數名都是直接賦值的,也就是在這個函數解析的時候就會進行賦值。
如果你還是不理解建議多看幾遍,另外如果你是js的新朋友一定要看什么是作用域鏈,什么是原型鏈,它們的區別,在js中它們具體指什么?這篇文章。