
提升:1. 變量提升 2. 函數(shù)提升
在解釋提升之前,有必要先了解一下作用域 和作用域鏈
注意:以下解釋非官方,個(gè)人理解
作用域:程序源代碼中定義這個(gè)變量的區(qū)域
作用域鏈:當(dāng)代碼在一個(gè)環(huán)境中執(zhí)行時(shí),會(huì)創(chuàng)建變量對(duì)象的一個(gè)作用域鏈來保證對(duì)執(zhí)行環(huán)境有權(quán)訪問的變量和函數(shù)的有序訪問
eg:
var a=2; console.log(a); <!-- a在全局作用域中 輸出 2--> function testa(){ var a=3; console.log(a) } <!--a 既在全局作用域中又在局部作用域中,輸出 3--> function testaa (){ console.log(a); } <!--a輸出 2-->解釋:
a 在全局作用域中,在testa作用域中。
testa()執(zhí)行時(shí)瀏覽器會(huì)詢問引擎在哪里見過 a的聲明,引擎會(huì)優(yōu)先在當(dāng)前作用域?qū)ふ?,找到?既返回給客戶端,所以在testa()執(zhí)行時(shí),輸出的a=3;
testaa()執(zhí)行時(shí) 也是現(xiàn)在testaa的作用域中查找,發(fā)現(xiàn)并沒有a,然后會(huì)順著作用域鏈查找到全局作用域中的a,所以在testaa()中輸出的不是 undefined 也不是RefrenceError 而是 2
- 變量提升
console.log(a)
var a = 2;
<!--輸出 undefined-->
為什么不是RefrenceError?
由于js是編譯語言,在引擎進(jìn)程編譯的過程中會(huì)先進(jìn)行變量的聲明,然后才會(huì)進(jìn)行賦值操作,所以上述代碼實(shí)際的執(zhí)行過程是這樣的:
var a ;
console.log(a);
a =2 ;
由于變量存在提升現(xiàn)象,會(huì)出現(xiàn)很多問題,其中就包括閉包(這里只簡(jiǎn)要介紹,詳見js基礎(chǔ)(2)):
var a=[];
for(var i =0;i<3;i++){
a[i]=function(){
return i;
}
}
console.log(a[0]()); // 3
console.log(a[1]()); // 3
console.log(a[2]()); // 3
為什么會(huì)全是3 呢
因?yàn)樵趫?zhí)行a[0]()時(shí),在該函數(shù)的作用域中沒有i的定義,所以回去找全局作用域中的i的值 此時(shí)在全局作用域中i 的值為3,所以所有的函數(shù)執(zhí)行之后都是 3;
解決方式:
var a=[];
for(var i =0;i<3;i++){
a[i]=function(i){
return function(){return i}
}(i)
}
console.log(a[0]()); // 0
console.log(a[1]()); // 1
console.log(a[2]()); // 2
相當(dāng)于在
a[i]這個(gè)函數(shù)的作用域中聲明了一個(gè)i變量 并且賦予了不同的值,所以會(huì)輸出 0 1 2
ES6 中針對(duì)變量的提升給出了一種解決方案,新增了兩種變量類型 const 和let,用這兩種類型聲明的變量存在暫時(shí)性死區(qū),并且在編譯階段 由const和let聲明的變量是未定義狀態(tài),所以就避免了變量提升。
console.log(a) ; //RefrenceError 未定義
let a =3;
var a=[];
for(let i =0;i<3;i++){
a[i]=function(){
return i;
}
}
console.log(a[0]()); // 0
console.log(a[1]()); // 1
console.log(a[2]()); // 2 解決閉包問題
- 函數(shù)提升
test(); //輸出test
function test(){
console.log('test');
}
test()執(zhí)行時(shí) 并沒有報(bào)錯(cuò),這就由于函數(shù)提升
由變量定義的函數(shù) 不提升,但是也存在變量聲明的提升
console.log(test());
var test =function (){
console.log('test');
}
輸出 TypeError test不是一個(gè)函數(shù) ,
console.log(test);輸出 test為undefined,還是會(huì)存在變量提升的現(xiàn)象
console.log(test());
const test =function (){
console.log('test');
}
輸出 RefrenceError test 未定義 ,同樣說明由const let定義的在預(yù)編譯階段都認(rèn)為沒有定義過,只有賦值完成之后才能引用