淺析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是單線程語(yǔ)言,所以執(zhí)行肯定是按順序執(zhí)行。但是并不是逐行的分析和執(zhí)行,而是一段一段地分析執(zhí)行,會(huì)先進(jìn)行編譯階段然后才是執(zhí)行階段。
在編譯階段階段,代碼真正執(zhí)行前的幾毫秒,會(huì)檢測(cè)到所有的變量和函數(shù)聲明,所有這些函數(shù)和變量聲明都被添加到名為Lexical Environmen
t的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í)行代碼到賦值語(yǔ)句時(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
聲明的變量沒(méi)有被“提升”嗎?
事實(shí)上所有的聲明(function, var, let, const, class)都會(huì)被“提升”。但是只有使用var
關(guān)鍵字聲明的變量才會(huì)被初始化undefined
值,而let
和const
聲明的變量則不會(huì)被初始化值。
只有在執(zhí)行階段JavaScript引擎在遇到他們的詞法綁定(賦值)時(shí),他們才會(huì)被初始化。這意味著在JavaScript引擎在聲明變量之前,無(wú)法訪問(wèn)該變量。這就是我們所說(shuō)的Temporal Dead Zone,即變量創(chuàng)建和初始化之間的時(shí)間跨度,它們無(wú)法訪問(wèn)。
如果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)境中的值,如果只是聲明了變量沒(méi)有被賦值,那么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)文章
JavaScript異步調(diào)用定時(shí)方法并停止該方法實(shí)現(xiàn)代碼
JavaScript異步調(diào)用定時(shí)方法并停止該方法實(shí)現(xiàn)代碼 ,需要的朋友可以參考下2012-03-03JavaScript基礎(chǔ)之流程控制語(yǔ)句的用法
下面就為大家?guī)?lái)一篇JavaScript基礎(chǔ)之流程控制語(yǔ)句的用法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-08-08JS實(shí)現(xiàn)json的序列化和反序列化功能示例
這篇文章主要介紹了JS實(shí)現(xiàn)json的序列化和反序列化功能,結(jié)合具體實(shí)例形式分析了javascript針對(duì)json的序列化與反序列化相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下2017-06-06微信小程序嵌入H5頁(yè)面(web-view)的方法詳解
使用<web-view>標(biāo)簽?zāi)茉谛〕绦蛑写蜷_(kāi)外部網(wǎng)頁(yè),但是要打開(kāi)的網(wǎng)頁(yè)的域名必須跟小程序的業(yè)務(wù)域名(業(yè)務(wù)域名可以在小程序的后臺(tái)管理界面添加)一致,否則在真機(jī)上是打不開(kāi)的,下面這篇文章主要給大家介紹了關(guān)于微信小程序嵌入H5頁(yè)面(web-view)的相關(guān)資料,需要的朋友可以參考下2022-09-09js中document.referrer實(shí)現(xiàn)移動(dòng)端返回上一頁(yè)
本文主要介紹了document.referrer實(shí)現(xiàn)移動(dòng)端返回上一頁(yè)的方法,具有很好的參考價(jià)值,下面跟著小編一起來(lái)看下吧2017-02-02