很多時候,在直覺上,我們都會認為js**在執行時都是自上而下一行一行執行的,但是實際上,有一種情況會導致這個假設是錯誤的。
按照傳統眼光,console.log(a)輸出的應該是undefined,因為var a在a = 2之後。但是,輸出的是2。a = 2;
var a;
console.log(a);
再看第二段**:
按照傳統眼光,console.log(a)輸出的應該是undefined,因為var a在a = 2之後。但是,輸出的是2。console.log(a);
var a = 2;
再看第二段**:
有人會想到第一段**,然後回答undefined。還有人會認為a在使用前未被宣告,因此丟擲referenceerror異常。遺憾的是,結果是undefined。console.log(a);
var a = 2;
為什麼呢?
從編譯器的角度看問題
js在編譯階段,編譯器的一部分工作就是找到所有宣告,並用合適的作用域將他們關聯起來。對於一般人來說var a = 2僅僅是乙個宣告,但是,js編譯器會將該段**拆為兩段,即:var a和a = 2。var a這個定義宣告會在編譯階段執行,而a = 2這個賦值宣告會在原地等待傳統意義上的從上到下的執行。
所以,在編譯器的角度來看,第一段**實際上是這樣的:
所以,輸出的是2。var a; // 編譯階段執行
a = 2;
console.log(a);
類似的,第二個**片段實際上是這樣執行的:
這樣的話,很明顯,輸出的應該是undefined,因為只對a進行了定義宣告,沒有對a進行賦值宣告。var a;
console.log(a);
a = 2;
從上面這兩個例子可以看出,變數宣告會從它們在****現的位置被移動到當前作用域的最上方進行執行,這個過程叫做提公升。
函式提公升
下面,再來看一段**
說到這裡,你是不是認為提公升很簡單,只要把變數都放到當前作用域最上方執行就好了?foo();
function foo ()
在這個例子中,輸出undefined而不會報錯,因為,函式變數也能提公升。即,實際上像如下的情況執行。
function foo ()
foo();
下面,我來說一種意外情況:函式表示式的提公升情況。
函式表示式的提公升情況
你是不是想說,這個例子不是和之前的那個差不多嗎?輸出的當然是undefined呀。但是,結果是,不輸出,因為js報了typeerror錯誤!foo();
var foo = function bar ()
因為,函式表示式不會進行提公升!
該例子的實際運**況是這樣的:
由於執行時,在作用域中找得到foo(該作用域最上方宣告了foo),所以不會報referenceerror錯誤,但是,foo此時沒有進行賦值(如果foo是乙個函式宣告而不是函式表示式,那麼就會賦值),也就是說實際上foo()是對乙個值為undefined的變數進行函式呼叫,所以,理所應當丟擲typeerror異常。var foo;
foo();
foo = function bar ()
值得一提的是,即使是具名的函式表示式,名稱識別符號在賦值之前也無法在所在作用域中使用,即:
函式優先foo(); // typeerror
bar(); // referenceerror
var foo = function bar () {}
函式宣告和變數宣告都會被提公升,但是有乙個值得注意的細節,那就是,函式會首先提公升,然後才是變數!
看下面這一段**:
這一段**會輸出1,原因就在於,函式優先。foo();
var foo;
function foo ()
foo = function ()
這一段**可以轉換為以下形式:
如果,在**的結尾再執行一次foo函式,此時,輸出的是1。function foo ()
var foo; // 重複宣告,被忽略
foo(); // 輸出1
foo = function ()
因為,儘管重複的宣告會被忽略了,但是後面的函式還是可以覆蓋前面的函式。function foo ()
var foo; // 重複宣告,被忽略
foo(); // 輸出1
foo = function ()
foo(); // 輸出2
明白了這個道理,你就可以理解下面這個問題了:
你猜這道題輸出的結果是什麼?是b!為什麼?因為foo進行了兩次的宣告,但是,後一次函式覆蓋了前一次的函式。所以呼叫foo時,永遠呼叫的都是console.log("b")。foo();
var a = true;
if (a)
} else //
}//幫助突破技術瓶頸,提公升思維能力
總結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 ...