先來看兩個栗子,下面的兩段**分別輸出什麼?
// **段1
function foo()
console.log(a);
}foo();
// **段2
function foo()
console.log(a);
}foo();
答案是:**段1列印的是1,**段2列印的是 a() 函式。
為什麼會這樣呢?這就涉及到js中的變數提公升和函式提公升的具體過程了。
js是怎麼建立變數的呢?
如下面的**:
var a = 1;
var b = 2;
js在解析上面的**的時候,其實會按照下面的方式進行解析的:
var a;
var b;
a = 1;
b = 2;
所以 js 並不是在我們定義乙個變數的時候,宣告完成之後立即賦值,而是把所有用到的變數全部宣告之後,再到變數的定義的地方進行賦值,變數的宣告的過程就是變數的提公升。
所以我們看下下面的栗子:
function foo()
foo();
上面的**在js的眼中是這樣解析的:
function foo()
foo();
所以輸出的 a 的值為1, b的值為 undefined。
變數在宣告提公升的時候,是全部提公升到作用域的最前面,乙個接著乙個的。但是在變數賦值的時候就不是乙個接著乙個賦值了,而是賦值的位置在變數原本定義的位置。原本js定義變數的地方,在js執行到這裡的時候,才會進行賦值操作,而沒有執行到的變數,不會進行賦值操作。
所以變數的提公升,提公升的其實是變數的宣告,而不是變數的賦值。
函式的提公升和變數的提公升類似,都是提公升到作用域的最開始的位置,只不過變數的提公升是分兩步的,第一步是變數宣告的提公升,第二步是變數的賦值。而函式的提公升是直接將整個函式整體提公升到作用域的最開始位置,相當於剪下過去的樣子。
在作用域中,不管是變數還是函式,都會提公升到作用域最開始的位置,不同的是,函式的提公升後的位置是在變數提公升後的位置之後的。
舉個栗子:
下面的**輸出什麼?
function foo()
console.log(a);
}foo();
上面的**在js眼中是這樣解析的:
function foo()
console.log(a); // a()
a = 1;
console.log(a); // 1
console.log(a); // 1
}foo();
所以從上面的栗子可以看到,變數的提公升是在函式提公升之前的,但是變數賦值的部分是在js原型到變數定義的位置才給變數賦值的,而函式提公升是相當於直接剪下到最前面的。
我們再看乙個更加複雜一點的栗子:
function foo()
console.log(a);
console.log(b);
var b = 2;
console.log(b);
function b() {}
console.log(b);
}foo();
js是這樣解析的:
function foo()
function b() {}
console.log(a); // a()
a = 1;
console.log(a); // 1
console.log(a); // 1
console.log(b); // b()
b = 2;
console.log(b); // 2
console.log(b);// 2
}foo();
最後,注意:只有宣告的變數和函式才會進行提公升,隱式全域性變數不會提公升。
下面的栗子中,b不會進行變數提公升。
function foo()
foo();
js變數提公升與函式提公升的詳細過程
在這裡我會從 web 前端零基礎開始,一步步學習 web 相關的知識點,期間也會分享一些好玩的專案。現在就讓我們一起進入 web 前端學習的冒險之旅吧!先來看兩個栗子,下面的兩段 分別輸出什麼?段1 function foo console.log a foo 段2 function foo con...
JS 變數提公升與函式提公升
在 es6 出來之前,沒有塊級作用域,只有全域性作用域 和 函式作用域。變數提公升指的是 將變數宣告提公升到它所在作用域的最開始部分。例子 console.log foo undefined var foo 變數提公升 console.log foo 變數提公升 相當於 var foo consol...
變數提公升與函式提公升
定義 var宣告的變數,js在執行時會將其宣告提公升到它所在作用域的頂端去執行,到我們 所在的位置來賦值。console.log a undefinded,因為一開始執行了var a var a 123console.log v1 undefined var v1 100 function func...