淺析JavaScript中的變量提升
前言:
JavaScript中奇怪的一點(diǎn)是你可以在變量和函數(shù)聲明之前使用它們。就好像是變量聲明和函數(shù)聲明被提升了代碼的頂部一樣。
sayHi() // Hi there!
function sayHi() {
console.log('Hi there!')
}
name = 'John Doe'
console.log(name) // John Doe
var name然而JavaScript并不會(huì)移動(dòng)你的代碼,所以JavaScript中“變量提升”并不是真正意義上的“提升”。
JavaScript是單線程語言,所以執(zhí)行肯定是按順序執(zhí)行。但是并不是逐行的分析和執(zhí)行,而是一段一段地分析執(zhí)行,會(huì)先進(jìn)行編譯階段然后才是執(zhí)行階段。
在編譯階段階段,代碼真正執(zhí)行前的幾毫秒,會(huì)檢測(cè)到所有的變量和函數(shù)聲明,所有這些函數(shù)和變量聲明都被添加到名為Lexical Environment的JavaScript數(shù)據(jù)結(jié)構(gòu)內(nèi)的內(nèi)存中。所以這些變量和函數(shù)能在它們真正被聲明之前使用。
函數(shù)提升
sayHi() // Hi there!
function sayHi() {
console.log('Hi there!')
}因?yàn)楹瘮?shù)聲明在編譯階段會(huì)被添加到詞法環(huán)境(Lexical Environment)中,當(dāng)JavaScript引擎遇到sayHi()函數(shù)時(shí),它會(huì)從詞法環(huán)境中找到這個(gè)函數(shù)并執(zhí)行它。
lexicalEnvironment = {
sayHi: < func >
}var變量提升
console.log(name) // 'undefined' var name = 'John Doe' console.log(name) // John Doe
上面的代碼實(shí)際上分為兩個(gè)部分:
var name表示聲明變量name= 'John Doe'表示的是為變量name賦值為'John Doe'。
var name // 聲明變量 name = 'John Doe' // 賦值操作
只有聲明操作var name會(huì)被提升,而賦值這個(gè)操作并不會(huì)被提升,但是為什么變量name的值會(huì)是undefined呢?
原因是當(dāng)JavaScript在編譯階段會(huì)找到var關(guān)鍵字聲明的變量會(huì)添加到詞法環(huán)境中,并初始化一個(gè)值undefined,在之后執(zhí)行代碼到賦值語句時(shí),會(huì)把值賦值到這個(gè)變量。
// 編譯階段
lexicalEnvironment = {
name: undefined
}
// 執(zhí)行階段
lexicalEnvironment = {
name: 'John Doe'
}所以函數(shù)表達(dá)式也不會(huì)被“提升”。helloWorld是一個(gè)默認(rèn)值是undefined的變量,而不是一個(gè)function。
helloWorld(); // TypeError: helloWorld is not a function
var helloWorld = function(){
console.log('Hello World!');
}let & const提升
console.log(a) // ReferenceError: a is not defined let a = 3
為什么會(huì)報(bào)一個(gè)ReferenceError錯(cuò)誤,難道let和const聲明的變量沒有被“提升”嗎?
事實(shí)上所有的聲明(function, var, let, const, class)都會(huì)被“提升”。但是只有使用var關(guān)鍵字聲明的變量才會(huì)被初始化undefined值,而let和const聲明的變量則不會(huì)被初始化值。
只有在執(zhí)行階段JavaScript引擎在遇到他們的詞法綁定(賦值)時(shí),他們才會(huì)被初始化。這意味著在JavaScript引擎在聲明變量之前,無法訪問該變量。這就是我們所說的Temporal Dead Zone,即變量創(chuàng)建和初始化之間的時(shí)間跨度,它們無法訪問。
如果JavaScript引擎在let和const變量被聲明的地方還找不到值的話,就會(huì)被賦值為undefined或者返回一個(gè)錯(cuò)誤(const的情況下)。
舉例:
let a console.log(a) // undefined a = 5
在編譯階段,JavaScript引擎遇到變量a并將它存到詞法環(huán)境中,但因?yàn)槭褂?code>let關(guān)鍵字聲明的,JavaScript引擎并不會(huì)為它初始化值,所以在編譯階段,此刻的詞法環(huán)境像這樣:
lexicalEnvironment = {
a: <uninitialized>
}如果我們要在變量聲明之前使用變量,JavaScript引擎會(huì)從詞法環(huán)境中獲取變量的值,但是變量此時(shí)還是uninitialized狀態(tài),所以會(huì)返回一個(gè)錯(cuò)誤ReferenceError。
在執(zhí)行階段,當(dāng)JavaScript引擎執(zhí)行到變量被聲明的時(shí)候,如果聲明了變量并賦值,會(huì)更新詞法環(huán)境中的值,如果只是聲明了變量沒有被賦值,那么JavaScript引擎會(huì)給變量賦值為undefined。
tips: 我們可以在let和const聲明之前使用他們,只要代碼不是在變量聲明之前執(zhí)行:
function foo() {
console.log(name)
}
let name = 'John Doe'
foo() // 'John Doe'Class提升
同let和const一樣,class在JavaScript中也是會(huì)被“提升”的,在被真正賦值之前都不會(huì)被初始化值, 同樣受Temporal Dead Zone的影響。
let peter = new Person('Peter', 25) // ReferenceError: Person is not defined
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
}
let John = new Person('John', 25);
console.log(John) // Person { name: 'John', age: 25 }到此這篇關(guān)于淺析JavaScript中的變量提升的文章就介紹到這了,更多相關(guān)JS變量提升內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Echarts橫向堆疊柱狀圖和markLine實(shí)例詳解
一些柱形圖在數(shù)據(jù)量比較多的時(shí)候,橫向排列受到擠壓,導(dǎo)致柱形圖,變的非常細(xì),影響整體的效果,所以應(yīng)該將柱形圖堆疊起來,這樣就會(huì)好很多,下面這篇文章主要給大家介紹了關(guān)于Echarts橫向堆疊柱狀圖和markLine的相關(guān)資料,需要的朋友可以參考下2022-06-06
js 動(dòng)態(tài)生成json對(duì)象、時(shí)時(shí)更新json對(duì)象的方法
下面小編就為大家?guī)硪黄猨s 動(dòng)態(tài)生成json對(duì)象、時(shí)時(shí)更新json對(duì)象的方法。小編覺的挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2016-12-12
微信小程序頁面滑動(dòng)屏幕加載數(shù)據(jù)效果
這篇文章主要為大家詳細(xì)介紹了微信小程序頁面滑動(dòng)屏幕加載數(shù)據(jù)效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-08-08
玩轉(zhuǎn)JavaScript OOP - 類的實(shí)現(xiàn)詳解
下面小編就為大家?guī)硪黄孓D(zhuǎn)JavaScript OOP - 類的實(shí)現(xiàn)詳解。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2016-06-06
js字符串去重復(fù)id的實(shí)現(xiàn)代碼
最近由于需要我們將相關(guān)id的重復(fù)的去掉,一個(gè)是客戶端一個(gè)后臺(tái)程序把關(guān),這里分享下js的去重復(fù)id的實(shí)現(xiàn)代碼2013-07-07
關(guān)于JavaScript中的數(shù)組方法和循環(huán)
這篇文章主要介紹了關(guān)于JavaScript中的數(shù)組方法和循環(huán),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-09-09
微信小程序地圖繪制線段并且測(cè)量(實(shí)例代碼)
這篇文章主要介紹了微信小程序地圖繪制線段并且測(cè)量,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-01-01

