?在文章開始之前附上之前一段代碼,它會(huì)輸出什么呢?
fn()
console.log(a)
a = 2
console.log(a)
var a = 3
console.log(a)
function fn() {
console.log(a)
var a = 4
console.log(a)
}
?眾所周知js屬于解釋型語言,它是執(zhí)行的時(shí)候才會(huì)編譯,是可以在解釋器中直接執(zhí)行的語言,不需要編譯;js在執(zhí)行時(shí)分為三個(gè)階段,語法檢測,預(yù)編譯和解釋執(zhí)行。
- 語法檢測階段:檢查代碼有無語法錯(cuò)誤
- 預(yù)編譯階段:創(chuàng)建上下文對(duì)象,var聲明的變量作為上下文屬性,用undefined進(jìn)行初始化,function聲明的函數(shù)也作為上下文對(duì)象,但是是保持了定義內(nèi)容的。另外,function聲明的優(yōu)先級(jí)是高于var的。這就是var和function的變量提升
- 解釋執(zhí)行:在解釋執(zhí)行過程中,變量在解析時(shí)先按照上下文對(duì)象尋找,如果沒有則按照上下文對(duì)象的原型鏈尋找,還尋找不到就會(huì)去上級(jí)作用域?qū)ふ摇?/li>
學(xué)了這個(gè)編譯原理,上面的代碼就很簡單了
fn() // function聲明的函數(shù)最優(yōu)先 輸出undefined 4
console.log(a) // var變量提升 輸出undefined
a = 2
console.log(a) // 輸出 2
var a = 3
console.log(a) // 輸出 3
function fn() {
console.log(a) // var變量提升,a優(yōu)先在本上下文對(duì)象中尋找,故輸出undefined
var a = 4 // 變量提升
console.log(a) // 變量賦值 輸出4
}
// 輸出順序?yàn)閡ndefined 4 undefined 2 3
b() // function 變量提升所以輸出22
var b = function () {
console.log(11)
}
b() // b被賦值所以輸出11
function b() {
console.log(22)
}
b() // function被提升所以輸出11
下面是一些關(guān)于變量提升相關(guān)的面試題
例 1:var 聲明的變量提升的問題,var 聲明的變量會(huì)提升到作用域最頂部,而賦值會(huì)保留在原位,所以 a 是 undefined;因?yàn)?let,const 沒有變量提升,所以打印 b 會(huì)報(bào)錯(cuò)無法在初始化之前訪問 b
/* var聲明變量提升的問題 */
console.log(a) // undefined
var a = 12
console.log(a) // 12
console.log(b); // Error:Cannot access 'b' before initialization
let b = 13;
例 2: var 變量提升,且不會(huì)形成塊級(jí)作用域,所以 var 聲明會(huì)提升到 fn 函數(shù)的最頂部,故 a 為 undefined,因?yàn)?a 為 undefined,所以不會(huì)進(jìn)入 if 里面,故打印為 undefined
function fn(){
if(a){
var a = 100
}
console.log(a) // undefined
}
fn()
例 3:在 fn 函數(shù)內(nèi) var 變量提升,所以 a=undefined,進(jìn)入 if 內(nèi)部賦值 a=4
var a = 100
function fn(){
if(a === undefined){
var a = 4
}
console.log(a) // 4
}
fn()
例 4:function 聲明會(huì)整個(gè)提升,而且優(yōu)先級(jí)比 var 申明高,所以后面 fn=test 會(huì)把函數(shù)聲明給覆蓋掉
var fn = 'test'
function fn(){
console.log('ss')
}
console.log(fn) // test
fn() // Error: fn is not a function
例 5:function 變量提升,后面被 fn 賦值覆蓋
var fn = function(){
console.log(1)
}
function fn(){
console.log(2)
}
fn() // log 1