函式提公升和變數提公升的理解

2022-08-20 15:18:13 字數 1628 閱讀 8897

下面我們來看兩個例子

1.

a = 2;

var a;

console.log(a)

這裡你可能會認為輸入的結果是undefined,因為 var a 宣告在 a = 2 之後,會把之前的宣告復蓋掉,所以結果是 undefined。但實際上列印的結果會是2

2.

console.log(a);

var a = 2;

鑑於上乙個**片段所表現出來的某種非自上而下的行為特點,你可能會認為這個**片段也會有同樣的行為而輸出 2。還有人可能會認為,由於變數 a 在使用前沒有先進行宣告,因此會丟擲 referenceerror 異常。

不幸的是兩種猜測都是不對的。輸出來的會是 undefined。

分析之前需要了解的知識點——編譯原理。

想要深入理解這個問題出現的原因,我們必須對編譯的過程有所了解。

如果你曾經了解過其他程式語言,比如c,c++,在**生成之前都需要在編輯器當中經歷 編譯 這乙個步驟。在傳統的編譯語言中,程式中的一段源**在執行之前需要經歷三個步驟,統稱為「編譯」

1.詞法分析:

這個過程會將由字元組成的字串分解成(對於程式語言來說)有用的**塊,這些**塊被稱為詞法單元(token)。

2.語法分析

這個過程是將詞法單元流(陣列)轉換成乙個由元素逐級巢狀所組成的代表了程式語法結構的樹。這個樹被稱為「抽象語法樹」(abstract syntax tree,ast)。

3.**生成

簡單來說就是有某種方法可以將 var a = 2; 的 ast 轉化為一組機器指令,用來建立乙個叫作 a 的變數(包括分配記憶體等),並將乙個值儲存在 a 中。

根據編譯原理繼續分析

分析的正確思路:包括變數和函式在內的所有宣告都會在任何**被執行前首先被處理。

舉個例子,var a = 2;你可能會認識這是乙個宣告,是乙個步驟,但是實際上會js將其看成兩個宣告過程,var a 和 a = 2;第乙個定義宣告是在編譯階段進行的。第二個賦值宣告會被留在原地等待執行階段。

我們回看一開始的兩個例子。

1.

var a;

a = 2;

console.log(a) //所以a為2

var a;

console.log(a);

a = 2;

其實可以這麼理解:當我們遇見乙個變數的宣告時,會把他放(移動)到**體的最上方,這個過程稱之為「提公升」。 需要注意 :提公升的只有宣告,而其他的輔助和邏輯並不會提公升。

函式提公升的方式和變數提公升有一些類似,函式提公升會把函式的宣告「移動到」**體的最上方。

舉個例子

1.函式宣告的方式

fun1();// 可以被呼叫

function fun1 ()

2.函式表示式的方式

fun2();// 不是 referenceerror, 而是 typeerror!

var fun2 = function bar()

執行的過程相當於

var fun2

fun2()

fun2 = function bar()

變數提公升和函式提公升

1.變數宣告提公升 通過var 定義 宣告 的變數,在定義語句之前就可以訪問到。值 undefined console.log a undefined var a 23 console.log a 23上面 等價於 var a 預編譯,將變數宣告提公升至當前作用域的頂端,初始值為undefined ...

變數提公升和函式提公升

首先js引擎在讀取js 時會進行兩個步驟,第乙個步驟是解釋,第二個步驟是執行。所謂解釋就是會先通篇掃瞄所有的js 然後把所有宣告提公升到頂端,第二步是執行,執行就是操作一類的。例子1 console.log a 輸出結果 undefined var a 10 script 以上 輸出 undefin...

深入理解js的變數提公升和函式提公升

一 變數提公升 在es6中提出了塊級作用域,用var宣告的變數,起作用域應為對整個塊都起作用,所以會跑偏 而且使用var宣告的變數會出現 變數提公升 現象。那麼什麼是變數提公升呢?用以下 直觀感受一下 其執行順序應為 二 函式提公升 js中建立函式有兩種方式 函式宣告式和函式字面量式。只有函式宣告才...