很多時候,在直覺上,我們都會認為js**在執行時都是自上而下一行一行執行的,但是實際上,有一種情況會導致這個假設是錯誤的。
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。
為什麼呢?
從編譯器的角度看問題
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 //面向1-3年前端人員
}//幫助突破技術瓶頸,提公升思維能力
你猜這道題輸出的結果是什麼?是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。再看第二段 ...
深入理解JS中的函式宣告提公升和變數宣告提公升
簡介 本文先從函式的宣告方式說起,介紹不同函式的宣告方式在函式宣告提公升上的不同。然後根據具體的例子比較變數宣告提公升和函式宣告提公升的不同。第一部分 函式的宣告方式 函式宣告有三種方式 函式宣告,函式表示式 又稱函式字面量宣告 函式物件的宣告 使用率很低 方式一 函式宣告 function 函式名...
js變數宣告
var a 向系統要個空間 var 是個關鍵字,變數宣告只有var var a 10 這裡發生兩個過程,乙個是向系統要個空間,另乙個是把10放進房間。並且先發生第一步。var a 10 a 20 20的值把10的值覆蓋 var a,b,c,e 可以同時宣告多個變數,中間以,號 程式設計都是英文狀態 ...