JS變數宣告和函式宣告提公升

2021-09-12 23:58:26 字數 2910 閱讀 7203

很多時候,在直覺上,我們都會認為js**在執行時都是自上而下一行一行執行的,但是實際上,有一種情況會導致這個假設是錯誤的。

a = 2;

var a;

console.log(a);

按照傳統眼光,console.log(a)輸出的應該是undefined,因為var a在a = 2之後。但是,輸出的是2。

再看第二段**:

console.log(a);

var a = 2;

按照傳統眼光,console.log(a)輸出的應該是undefined,因為var a在a = 2之後。但是,輸出的是2。

再看第二段**:

console.log(a);

var a = 2;

有人會想到第一段**,然後回答undefined。還有人會認為a在使用前未被宣告,因此丟擲referenceerror異常。遺憾的是,結果是undefined。

為什麼呢?

從編譯器的角度看問題

js在編譯階段,編譯器的一部分工作就是找到所有宣告,並用合適的作用域將他們關聯起來。對於一般人來說var a = 2僅僅是乙個宣告,但是,js編譯器會將該段**拆為兩段,即:var a和a = 2。var a這個定義宣告會在編譯階段執行,而a = 2這個賦值宣告會在原地等待傳統意義上的從上到下的執行。

所以,在編譯器的角度來看,第一段**實際上是這樣的:

var a;  // 編譯階段執行

a = 2;

console.log(a);

所以,輸出的是2。

類似的,第二個**片段實際上是這樣執行的:

var a;

console.log(a);

a = 2;

這樣的話,很明顯,輸出的應該是undefined,因為只對a進行了定義宣告,沒有對a進行賦值宣告。

從上面這兩個例子可以看出,變數宣告會從它們在****現的位置被移動到當前作用域的最上方進行執行,這個過程叫做提公升。

函式提公升

下面,再來看一段**

foo();

function foo ()

在這個例子中,輸出undefined而不會報錯,因為,函式變數也能提公升。即,實際上像如下的情況執行。

function foo ()

foo();

說到這裡,你是不是認為提公升很簡單,只要把變數都放到當前作用域最上方執行就好了?

下面,我來說一種意外情況:函式表示式的提公升情況。

函式表示式的提公升情況

foo();

var foo = function bar ()

你是不是想說,這個例子不是和之前的那個差不多嗎?輸出的當然是undefined呀。但是,結果是,不輸出,因為js報了typeerror錯誤!

因為,函式表示式不會進行提公升!

該例子的實際運**況是這樣的:

var foo;

foo();

foo = function bar ()

由於執行時,在作用域中找得到foo(該作用域最上方宣告了foo),所以不會報referenceerror錯誤,但是,foo此時沒有進行賦值(如果foo是乙個函式宣告而不是函式表示式,那麼就會賦值),也就是說實際上foo()是對乙個值為undefined的變數進行函式呼叫,所以,理所應當丟擲typeerror異常。

值得一提的是,即使是具名的函式表示式,名稱識別符號在賦值之前也無法在所在作用域中使用,即:

foo();  // typeerror

bar(); // referenceerror

var foo = function bar () {}

函式優先

函式宣告和變數宣告都會被提公升,但是有乙個值得注意的細節,那就是,函式會首先提公升,然後才是變數!

看下面這一段**:

foo();

var foo;

function foo ()

foo = function ()

這一段**會輸出1,原因就在於,函式優先。

這一段**可以轉換為以下形式:

function foo () 

var foo; // 重複宣告,被忽略

foo(); // 輸出1

foo = function ()

如果,在**的結尾再執行一次foo函式,此時,輸出的是1。

function foo () 

var foo; // 重複宣告,被忽略

foo(); // 輸出1

foo = function ()

foo(); // 輸出2

因為,儘管重複的宣告會被忽略了,但是後面的函式還是可以覆蓋前面的函式。

明白了這個道理,你就可以理解下面這個問題了:

foo();

var a = true;

if (a)

} else //

}//幫助突破技術瓶頸,提公升思維能力

你猜這道題輸出的結果是什麼?是b!為什麼?因為foo進行了兩次的宣告,但是,後一次函式覆蓋了前一次的函式。所以呼叫foo時,永遠呼叫的都是console.log("b")。

總結1.所有宣告(變數和函式)都會被移動到各自作用域的最頂端,這個過程被稱為提公升

2.函式表示式等各種賦值操作並不會被提公升

3.函式優先原則

4.盡量避免產生提公升問題

深入解析JS變數宣告和函式宣告提公升

很多時候,在直覺上,我們都會認為js 在執行時都是自上而下一行一行執行的,但是實際上,有一種情況會導致這個假設是錯誤的。a 2 var a console.log a 按照傳統眼光,console.log a 輸出的應該是undefined,因為var a在a 2之後。但是,輸出的是2。再看第二段 ...

變數宣告提公升 Vs 函式宣告提公升

先看以下 1 var in window a in window console.log in window 2 var in window a in window console.log in window if a in window 3 var a var in window a in win...

JS變數宣告提公升

js的變數作用域是離它最近的封閉語塊或 塊,包含他們內部的函式.在 塊中宣告會被隱式的提公升到封閉函式的頂部 1 function 6 var y 1 7 上面的 會被js解釋成下面的格式 1 function 8 有時候我們會不小心的在函式內部重新宣告了已有的變數 function text x ...