JS中的提升機制變量提升函數(shù)提升實例詳解
正文
對一些計算機語言來說,程序被執(zhí)行時,對命令的翻譯通常是自上而下逐行執(zhí)行的,這通常被稱為代碼解釋;
對另外一些語言來說,這種翻譯是預先進行的,被稱為代碼編譯,這樣在程序執(zhí)行的時候,運行的就是已經(jīng)編譯好的、可執(zhí)行的計算機指令。
JavaScript通常被認為是解釋型的,因為每次執(zhí)行js源碼時都需要進行處理。但這么說也不是完全準確的,我們需要知道,JavaScript引擎實際上是動態(tài)編譯程序,然后立即執(zhí)行編譯后的代碼。而JavaScript中的變量聲明和函數(shù)提升的直接原因就是編譯階段編譯器所做的事。
在提升過程中,雖然聲明似乎在程序中被提升了,但實際發(fā)生的事情是,函數(shù)和變量聲明在編譯階段被添加到內(nèi)存中。
一.變量提升
就變量和常量而言,關鍵字 var 被提升,let 和 const 不允許提升。
a = 5; console.log(a); var a; // 5
在上面的示例中,在聲明變量 a 之前使用它。程序運行并顯示輸出 5。該程序的作用如下:
var a; a = 5; console.log(a); // 5
然而在 JavaScript 中,初始化不會被提升。
console.log(a);//undefined var a = 5;
上述程序的作用如下:
var a; console.log(a); a = 5;
在編譯階段,只有聲明被移動到內(nèi)存中。因此,變量 a 的值是 undefined,因為 a 是在未初始化的情況下打印的。注意:當變量在函數(shù)內(nèi)部使用時,變量僅被提升到函數(shù)的頂部。
var a = 4; function greet() { b = 'hello'; console.log(b); var b; } greet(); // hello console.log(b);//Uncaught ReferenceError: b is not defined
如果變量與 let (const)關鍵字一起使用,則不會提升該變量。
a = 5; console.log(a);// error let a;
換一種角度說,變量與let(const)關鍵字一起使用,變量被提升到暫時性死區(qū)(TDZ)中,直到程序執(zhí)行到該變量的let(const)聲明語句的時候才從TDZ中被釋放。
二.函數(shù)提升
由于函數(shù)聲明和變量聲明都會被提升,函數(shù)會先被提升,然后才是變量,并且后面的函數(shù)聲明會覆蓋前面的。
代碼示例:
foo(); var foo; function foo(){ console.log(1); } foo = function(){ console.log(2); };
最終結果會輸出1。因為函數(shù)聲明會被提升,而函數(shù)表達式不會被提升。這段代碼可以理解成:
function foo(){ console.log(1); } foo(); foo = function(){ console.log(2); };
三.判斷順序
執(zhí)行函數(shù)中的第一行代碼時,如何判斷該函數(shù)的詞法作用域中存在哪些變量呢?該變量代表的是什么呢?判斷步驟如下:
- 將參數(shù)列表中的參數(shù)作為變量標識符存儲在作用域中,值為undefined;
- 將傳入的實參對應給相應的參數(shù)列表中的標識符賦值;
- 函數(shù)提升;若作用域中有與函數(shù)名同名的標識符,則該函數(shù)取代該標識符的值;
- var提升;若作用域中有同名的標識符,則不做任何改變,否則在作用域中添加該標識符,且值為undefined;
- 執(zhí)行第一行代碼。
四.其他“提升”
1.作為import結果的聲明是“提升的”;
foo(); import { foo } from "foo";
上面這段代碼中,foo()是可以運行的,不只是因為import...語句的靜態(tài)決議在編譯過程中確定了foo值是什么,也因為它“提升”了在模塊作用域頂層的聲明,使它在模塊所用位置可用。
以上就是JS中的提升機制變量提升函數(shù)提升實例詳解的詳細內(nèi)容,更多關于JS 變量提升函數(shù)提升的資料請關注腳本之家其它相關文章!
相關文章
