什么是變量提升
變量提升(Hoisting)被認(rèn)為是, JavaScript中執(zhí)行上下文 工作方式的一種認(rèn)識(shí)。從概念的字面意義上說,“變量提升”意味著變量和函數(shù)的聲明會(huì)在物理層面移動(dòng)到全局代碼或者代碼塊的最前面,但這么說并不準(zhǔn)確,實(shí)際上變量和函數(shù)聲明在代碼里的位置是不會(huì)動(dòng)的,而是在編譯階段被放入內(nèi)存中。
變量提升的各種情況
正常變量使用,先聲明再使用
bla = 2;var bla;console.log(bla);// 2//可以隱式地將以上代碼理解為var bla; // 變量聲明會(huì)提升到作用域頂部bal = 2; // 賦值會(huì)被保留在原位置console.log(bla);// 2
建議始終在作用域頂部聲明變量(全局代碼的頂部和函數(shù)代碼的頂部),這可以清楚知道哪些變量是函數(shù)作用域(局部),哪些變量在作用域鏈上解決。
在變量聲明之前使用
function doSomething() { console.log(bar); // undefined var bar = 111; console.log(bar); // 111}//可以隱式地將以上代碼理解為function doSomething() { var bar; //聲明提升至代碼塊頂部 console.log(bar); // undefined bar = 111; console.log(bar); // 111}
如果去除變量聲明
function doSomething() { console.log(bar); // Uncaught ReferenceError: bar is not defined}
同名變量多次聲明
同名變量多次聲明,重復(fù)的聲明會(huì)被忽略,每次賦值都會(huì)執(zhí)行,調(diào)用時(shí),使用最近的一次賦值。
// example 1var bar=9;console.log(bar);//9var bar;console.log(bar);//9// example 2var bar=9;console.log(bar);// 9 var bar=3;console.log(bar); // 3
函數(shù)聲明提升
JavaScript 中的函數(shù)聲明被提升到了函數(shù)定義。你可以在函數(shù)聲明之前使用該函數(shù):
hoisted(); // logs "foo"function hoisted() { console.log('foo');}//可以理解為function hoisted() { console.log('foo');}hoisted(); // logs "foo"
重復(fù)的函數(shù)聲明,后者會(huì)覆蓋前者。
hoisted(); // logs "bar"function hoisted() { console.log('foo');}function hoisted() { console.log('bar');}
注意:函數(shù)表達(dá)式不會(huì)被提升,如下:
notHoisted(); // TypeError: notHoisted is not a functionvar notHoisted = function() { //函數(shù)表達(dá)式 console.log('bar');};
變量提升也適用于其他數(shù)據(jù)類型和變量。變量可以在聲明之前進(jìn)行初始化和使用。但是如果沒有初始化,就不能使用它們。
JavaScript 只會(huì)提升聲明,不會(huì)提升其初始化。
函數(shù)和變量相比,會(huì)被優(yōu)先提升。這意味著函數(shù)會(huì)被提升到更靠前的位置。
let 與 const 對(duì)變量提升的影響
塊作用域
{ let a='test';}console.log(a); // throw Error: Uncaught ReferenceError: a is not defined
必須先聲明,再使用
let a = 1;function test() { console.log(a); const a = 2;}test(); // throw Error: Uncaught ReferenceError: can't access lexical declaration 'a' before initialization
同一作用域不能存在相同標(biāo)識(shí)符的變量或者函數(shù)
// example 1function test(params) { let params = 1;}test(0);// throw Error: Uncaught SyntaxError: redeclaration of formal parameter params // example 2function func() { let test = 1; let test = 3;}func();// throw Error: Uncaught SyntaxError: redeclaration of let test // example 3function func() { let inner=2; function inner (){ console.log(111); }}func();// throw Error: Uncaught SyntaxError: redeclaration of let inner
class關(guān)鍵字的在聲明方面類似let和const
// example 1{ class Test { }}var t1 = new Test();// throw Error: Uncaught ReferenceError: can't access lexical declaration 'Test' before initialization // example 2var t1=new Test();class Test{}// throw Error: Uncaught SyntaxError: redeclaration of let Test // example 3class Test{}var Test=1;// throw Error: Uncaught SyntaxError: redeclaration of class Test
參考
MDN:https://developer.mozilla.org/zh-CN/docs/Glossary/HoistingJavaScript變量提升總結(jié):https://juejin.cn/post/7050746117734023181