摘要:有意思的是,這意味著變量在聲明之前甚至已經(jīng)可用。的這個特性被非正式地稱為聲明提前,即函數(shù)里聲明的所有變量但不涉及賦值都被提前至函數(shù)體的頂部。但實際上會將其看成兩個聲明和。第二個賦值聲明會被留在原地等待執(zhí)行階段。
簡介
JavaScript的函數(shù)作用域是指在函數(shù)內(nèi)聲明的所有變量在函數(shù)體內(nèi)始終是可見的。有意思
的是,這意味著變量在聲明之前甚至已經(jīng)可用。JavaScript的這個特性被非正式地稱為
聲明提前(hoisting) ,即JavaScript函數(shù)里聲明的所有變量(但不涉及賦值)都被“提
前”至函數(shù)體的頂部。如果對提升不太明白的,請參考JavaScript高級程序設(shè)計177頁函數(shù)表達式.MDN變量提升
函數(shù)聲明: sayHi(); //不會報錯,在執(zhí)行代碼之前會先讀取函數(shù)聲明,也就是 函數(shù)聲明提升 function sayHi(){ alert("Hi") } 通過提升其實是這樣的: //函數(shù)聲明提升到頂部 function sayHi(){ alert("Hi") } sayHi(); //不會報錯
函數(shù)表達式: sayHi(); // 報錯 var sayHi = function(){ alert("Hi") } 函數(shù)表達式其實是創(chuàng)建一個匿名函數(shù)然后賦值給變量,通過提升應(yīng)該是這樣的: //函數(shù)聲明和變量聲明都被提升到作用域頂部,函數(shù)優(yōu)先 functionsayHi(){ alert("Hi") } //變量聲明被提升到頂部 var sayHi; sayHi(); // 報錯 //變量賦值被留在原地 sayHi = function(){ alert("Hi") }
函數(shù)提升優(yōu)先級高于變量提升 a() // alert(1) var a = 1 function a(){ alert(1) } 通過提升: function a(){ alert(1) } var a a() a = 1提問 為什么會有提升
比起那些編譯過程只有三個步驟的語言的編譯器,JavaScript引擎要復(fù)雜得多。例如,在語法分析 和代碼生成階段有特定的步驟來對運行性能進行優(yōu)化,包括對冗余元素進行優(yōu)化等。我們通過編譯器在詞法階段進行詞法分析,生成詞法作用域,詞法作用域就是用來管理引擎如何在當(dāng)前作用域以及嵌套 的子作用域中根據(jù)標(biāo)識符名稱進行變量查找。提升的作用使得所有聲明都在詞法作用域的上方,這樣引擎在作用域及嵌套作用域中變量查找可以更快更簡單。
提升的機制引擎會在解釋 JavaScript代碼之前首先對其進行編譯。編譯階段中的一部分工作就是找到所有的聲明,并用合適 的作用域?qū)⑺鼈冴P(guān)聯(lián)起來,這也正是詞法作用域的核心內(nèi)容。
因此,正確的思考思路是,包括變量和函數(shù)在內(nèi)的所有聲明都會在任何代碼被執(zhí)行前首先被處理。
當(dāng)你看到 var a = 2; 時,可能會認(rèn)為這是一個聲明。但JavaScript實際上會將其看成兩個聲 明: var a; 和 a = 2; 。第一個定義聲明是在編譯階段進行的。第二個賦值聲明會被留在原地等待執(zhí) 行階段。
MDN_let及暫存死區(qū)
var i = 10; function a(){ i = 3; var i = 1; //因為 var 提升了 所以在 function里 創(chuàng)建了 局部變量 i } console.log(i) // 10
let a = 1 { a = 2; let a = 3; //報錯 } //這里的報錯,我認(rèn)為是規(guī)范化強制性報錯,并不代表let沒有提升 //我的猜想如下, let a = 1 { let a // 暫存死區(qū) 開始的地方就是這里 a = 2 // 由于 a = 2 在 暫存死區(qū) 中,所以報錯 a // 暫存死區(qū) 結(jié)束的地方就是這里 }為什么let要強制性報錯
不推薦使用eval及with等,使用let/const 代替var,使用塊級作用域
目的就是為了,減少詞法欺騙以及作用域的混亂導(dǎo)致的性能問題,使得javascript引擎運行更快。
使用let 就要按照let 的使用規(guī)定,不然和使用var又沒什么區(qū)別了,這是我的想法。
未完待續(xù)...
歡迎補充批評...
參考文章:
知乎提問
strack overflow
JavaScript引擎解析預(yù)編譯
我的博客園
《你不知道的JavaScript 上》
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/95715.html
摘要:簡介變量提升意味著變量和函數(shù)的聲明會在物理層面移動到代碼的最前面,但這么說并不準(zhǔn)確。實際上變量和函數(shù)聲明在代碼里的位置是不會動的,而是在編譯階段被放入內(nèi)存中。 簡介 變量提升意味著變量和函數(shù)的聲明會在物理層面移動到代碼的最前面,但這么說并不準(zhǔn)確。 實際上變量和函數(shù)聲明在代碼里的位置是不會動的,而是在編譯階段被放入內(nèi)存中。 聲明變量的方法 var、let、const 不用以上關(guān)鍵字...
摘要:預(yù)編譯發(fā)生在函數(shù)執(zhí)行前也就是說函數(shù)執(zhí)行時,預(yù)編譯已經(jīng)結(jié)束。五總結(jié)理解預(yù)編譯需要明白變量函數(shù)聲明和變量賦值。預(yù)編譯階段,只進行變量函數(shù)聲明,不會進行變量的初始化即變量賦值,所有變量的值都是變量賦值是在解釋執(zhí)行階段才進行的。 一、JS的概念 JavaScript ( JS ) 是一種具有函數(shù)優(yōu)先的輕量級解釋型或即時編譯型的編程語言。 二、JS語言特點 2.1 單線程 (1)JavaScri...
摘要:所以形式參數(shù)是本地的,不是外部的或者全局的。這叫做函數(shù)聲明,函數(shù)聲明會連通命名和函數(shù)體一起被提升至作用域頂部。這叫做函數(shù)表達式,函數(shù)表達式只有命名會被提升,定義的函數(shù)體則不會。 Scoping & Hoisting var a = 1; function foo() { if (!a) { var a = 2; } alert(a); }; ...
摘要:在中,有四種方式可以讓命名進入到作用域中按優(yōu)先級語言定義的命名比如或者,它們在所有作用域內(nèi)都有效且優(yōu)先級最高,所以在任何地方你都不能把變量命名為之類的,這樣是沒有意義的形式參數(shù)函數(shù)定義時聲明的形式參數(shù)會作為變量被至該函數(shù)的作用域內(nèi)。 Scoping & Hoisting 例: var a = 1; function foo() { if (!a) { var ...
閱讀 3163·2021-11-04 16:09
閱讀 3131·2021-09-23 11:49
閱讀 3648·2021-09-09 09:33
閱讀 3633·2021-08-18 10:22
閱讀 2048·2019-08-30 15:55
閱讀 3636·2019-08-30 15:53
閱讀 2662·2019-08-28 18:08
閱讀 898·2019-08-26 18:18