JavaScript變數提升的理解
阿新 • • 發佈:2018-12-30
變數提升
先說三句總結性的話:
let 的「建立」過程被提升了,但是初始化沒有提升。
var 的「建立」和「初始化」都被提升了。
function 的「建立」「初始化」和「賦值」都被提升了。
所以,我們要注意,這三種變數提升,含義是不同的。
變數提升的規律
在進入一個執行上下文後,先把 var 和 function 宣告的變數前置,再去順序執行程式碼。
PS:作用域分為全域性作用域和函式作用域,用var宣告的變數,只在自己所在的所用域有效。
我們舉例來看看下面的程式碼。
程式碼 1:
console.log(fn); var fn = 1; function fn() { } console.log(fn);
相當於:
var fn = undefined;
function fn() {
}
console.log(fn);
fn = 1;
console.log(fn);
列印結果:
程式碼 2:
console.log(i);
for (var i = 0; i < 3; i++) {
console.log(i)
}
相當於:
var i = undefined; console.log(i); for (i = 0; i < 3; i++) { console.log(i); }
列印結果:
程式碼 3:
var a = 1;
function fn() {
a = 2;
console.log(a)
var a = 3;
console.log(a)
}
fn();
console.log(a);
相當於:
var a = undefined; function fn() { var a a = 2 console.log(a) a = 3 console.log(a) }; a = 1; fn(); console.log(a);
列印結果:
宣告時的重名問題
假設a
被宣告為變數,緊接著a
又被宣告為函式,原則是:宣告會被覆蓋(先來後到,就近原則)。
PS:
如果
a
已經有值,再用 var 宣告是無效的。如果
a
已經有值,緊接著又被賦值,則賦值會被覆蓋。
舉例1:
var fn; //fn被宣告為變數
function fn() {// fn被宣告為function,就近原則
}
console.log(fn); //列印結果:function fn(){}
舉例2:
function fn() {} //fn被宣告為function,且此時fn已經被賦值,這個值就是function的物件
var fn; //fn已經在上一行被宣告且已經有值, 再 var 無效,並不會重置為 undefined
console.log(fn) //列印結果:function fn(){}
既然再var無效,但是再function,是有效的:
function fn() {} //fn被宣告為function,且此時fn已經有值,這個值就是function的物件
function fn() { //此時fn被重複賦值,會覆蓋上一行的值
console.log('smyhvae');
}
console.log(fn)
列印結果:
函式作用域中的變數提升(兩點提醒)
提醒1:
在函式作用域也有宣告提前的特性:
使用var關鍵字宣告的變數,是在函式作用域內有效,而且會在函式中所有的程式碼執行之前被宣告
函式宣告也會在函式中所有的程式碼執行之前執行
因此,在函式中,沒有var宣告的變數都會成為全域性變數,而且並不會提前宣告。
舉例1:
var a = 1;
function foo() {
console.log(a);
a = 2; // 此處的a相當於window.a
}
foo();
console.log(a); //列印結果是2
上方程式碼中,foo()的列印結果是1
。如果去掉第一行程式碼,列印結果是Uncaught ReferenceError: a is not defined
提醒2:定義形參就相當於在函式作用域中聲明瞭變數。
function fun6(e) {
console.log(e);
}
fun6(); //列印結果為 undefined
fun6(123);//列印結果為123
其他題目
var a = 1;
if (a > 0) {
console.log(a);
var a = 2;
}
console.log(a);
列印結果:
1
2
上方程式碼中,不存在塊級作用域的概念。if語句中用var定義的變數,仍然是全域性變數。
順便延伸一下,用let定義的變數,是在塊級作用域內有效。