ES6 import會產生變數提升的現象。變數提升是將變數宣告提升到它所在作用域的最開始的部分。 js要經歷編譯跟執行階段,在編譯階段的時候,會蒐集所有的變量聲明並且提前聲明變量,而其他的語句都不會改變他們的順序,因此,在編譯階段的時候,第一步就已經執行了,而第二部則是在執行階段執行到該語句的時候才執行。
本教學操作環境:windows7系統、ECMAScript 6版、Dell G3電腦。
JavaScript是單執行緒語言,所以執行一定是依照順序執行。但不是逐行的分析和執行,而是一段一段地分析執行,會先進行編譯階段然後才是執行階段。在編譯階段階段,程式碼真正執行前的幾毫秒,會偵測到所有的變數和函數聲明,所有這些函數和變數聲明都被加入到名為Lexical Environment的JavaScript資料結構內的記憶體中。所以這些變數和函數能在它們真正被宣告之前使用。
先從一個簡單的例子來入手:
a = 2; var a; console.log(a);
以上的程式碼會輸出什麼,假如這段程式碼是從上到下執行的話,肯定會輸出undefined,然而JavaScript卻不是自上而下執行的語言。 這段程式碼的輸出結果是2,意外嗎?那麼,為什麼會這樣,這個關鍵點就在於--變數提升。他會將目前作用域的所有變數的聲明,提升到程式的頂部,因此,上面的程式碼等價於以下程式碼,這樣是不是就能明白一些了?
var a; a = 2; console.log(a);
那我們再看一個例子:
console.log(a); var a = 2;
這段程式碼又會輸出什麼?輸出2嗎? 其實這段程式碼會輸出undefined。這又是為什麼呢?剛剛說過,JavaScript會將變數的宣告提升到頂部,但是賦值語句是不會提升的,對於js來說,var a = 2是分為兩步解析的:
var a; a = 2;
而js只會提升var a 這句,所以剛剛的語句等價於:
var a; console.log(a); a = 2;
為什麼會出現變數提升這個現象呢? 因為js與其他語言一樣,都要經歷編譯跟執行階段。而js在編譯階段的時候,會蒐集所有的變數宣告並且提前宣告變量,而其他的語句都不會改變他們的順序,因此,在編譯階段的時候,第一步就已經執行了,而第二部則是在執行階段執行到該語句的時候才執行。
ES6 import 會產生變數提升的現象。
例如以下的測試程式碼,
// a.js console.log('I am a.js...') import { foo } from './b.js'; console.log(foo); // b.js console.log('I am b.js...') export let foo = 1;
運行a.js,
// node -r esm a.js I am b.js... I am a.js... 1
列印的結果是先出現'I am b.js...' ,然後再出現'I am a.js...',這就是變數提升的現象。
這是因為ES6 在語言標準層面上實作了模組功能,所以當對a.js預編譯時發現關鍵字import後,先去載入b.js,所以先輸出'I am b. js...'。
整個流程是,
變數提升的產生,其實與變數物件的建立過程有關。
變數物件創建過程
變數物件(Variable Object)的創建,依序經歷以下幾個步驟。
檢查目前上下文的函數聲明,也就是使用function關鍵字宣告的函數。在變數物件中以函數名建立一個屬性,屬性值為指向函數所在記憶體位址的參考。如果函數名的屬性已經存在,那麼該屬性將會被新的參考所覆寫。
檢查目前上下文中的變數聲明,每找到一個變數聲明,就在變數物件中以變數名稱建立屬性,屬性值為undefined。如果該變數名的屬性已經存在,為了防止同名的函數被修改為undefined,則會直接跳過,原屬性值不會被修改。
function宣告會比var宣告優先權更高一點。
function test() { console.log(a); console.log(foo()); var a = 1; function foo() { return 2; } } test();
直接從test()的執行上下文開始理解。
// 创建过程 testEC = { // 变量对象 VO: {}, // 作用域链 scopeChain: {} } // VO 为 Variable Object 的缩写,即变量对象 VO = { arguments: {...}, foo: <foo reference> // 表示foo的地址引用 a: undefined }
test()執行的結果是,
// node -r esm demo01.js undefined 2
其實,上面的程式碼demo01.js,變成了這樣的執行順序,
function test() { function foo() { return 2; } var a; console.log(a); console.log(foo()); a = 1; } test();
【相關推薦: javascript學習教學】
以上是es6 import會變數提升嗎的詳細內容。更多資訊請關注PHP中文網其他相關文章!