大家好,這里是「 從零開始學 Web 系列教程 」,並在下列地址同步更新......
- github:https://github.com/Daotin/Web
- 微信公眾號:Web前端之巔
- 博客園:http://www.cnblogs.com/lvonve/
在這里我會從 Web 前端零基礎開始,一步步學習 Web 相關的知識點,期間也會分享一些好玩的項目。現在就讓我們一起進入 Web 前端學習的冒險之旅吧!
js變量提升與函數提升的詳細過程
先來看兩個栗子,下面的兩段代碼分別輸出什么?
// 代碼段1
function foo() {
var a = 1;
function a() {}
console.log(a);
}
foo();
// 代碼段2
function foo() {
var a;
function a() {}
console.log(a);
}
foo();
答案是:代碼段1打印的是1,代碼段2打印的是 a() 函數。
為什么會這樣呢?這就涉及到js中的變量提升和函數提升的具體過程了。
1、變量的提升
js是怎么創建變量的呢?
如下面的代碼:
var a = 1;
var b = 2;
js在解析上面的代碼的時候,其實會按照下面的方式進行解析的:
var a;
var b;
a = 1;
b = 2;
所以 js 並不是在我們定義一個變量的時候,聲明完成之后立即賦值,而是把所有用到的變量全部聲明之后,再到變量的定義的地方進行賦值,變量的聲明的過程就是變量的提升。
所以我們看下下面的栗子:
function foo() {
var a = 1;
console.log(a);
console.log(b);
var b = 2;
}
foo();
上面的代碼在js的眼中是這樣解析的:
function foo() {
var a;
var b;
a = 1;
console.log(a); // 1
console.log(b); // undefined
b = 2;
}
foo();
所以輸出的 a 的值為1, b的值為 undefined。
變量在聲明提升的時候,是全部提升到作用域的最前面,一個接着一個的。但是在變量賦值的時候就不是一個接着一個賦值了,而是賦值的位置在變量原本定義的位置。原本js定義變量的地方,在js運行到這里的時候,才會進行賦值操作,而沒有運行到的變量,不會進行賦值操作。
所以變量的提升,提升的其實是變量的聲明,而不是變量的賦值。
2、函數的提升
函數的提升和變量的提升類似,都是提升到作用域的最開始的位置,只不過變量的提升是分兩步的,第一步是變量聲明的提升,第二步是變量的賦值。而函數的提升是直接將整個函數整體提升到作用域的最開始位置,相當於剪切過去的樣子。
3、變量提升和函數提升的順序
在作用域中,不管是變量還是函數,都會提升到作用域最開始的位置,不同的是,函數的提升后的位置是在變量提升后的位置之后的。
舉個栗子:
下面的代碼輸出什么?
function foo() {
console.log(a);
var a = 1;
console.log(a);
function a() {}
console.log(a);
}
foo();
上面的代碼在js眼中是這樣解析的:
function foo() {
var a;
function a() {}
console.log(a); // a()
a = 1;
console.log(a); // 1
console.log(a); // 1
}
foo();
所以從上面的栗子可以看到,變量的提升是在函數提升之前的,但是變量賦值的部分是在js原型到變量定義的位置才給變量賦值的,而函數提升是相當於直接剪切到最前面的。
我們再看一個更加復雜一點的栗子:
function foo() {
console.log(a);
var a = 1;
console.log(a);
function a() {}
console.log(a);
console.log(b);
var b = 2;
console.log(b);
function b() {}
console.log(b);
}
foo();
js是這樣解析的:
function foo() {
var a;
var b;
function a() {}
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() {
console.log(a);
console.log(b); // 報錯
b = 'aaa';
var a = 'bbb';
console.log(a);
console.log(b);
}
foo();
4、參考鏈接
js變量提升與函數提升的機制: https://segmentfault.com/a/1190000008568071