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