JavaScript變數提升的本質
變數提升
先說三句總結性的話:
- let 的「建立」過程被提升了,但是初始化沒有提升。
- var 的「建立」和「初始化」都被提升了。
- function 的「建立」「初始化」和「賦值」都被提升了。
所以,我們要注意,這三種變數提升,含義是不同的。
變數提升的規律
在進入一個執行內容後,先把 var 和 function 聲明的變數前置,再去順序執行代碼。
PS:範圍分為全域範圍和函數範圍,用var聲明的變數,只在自己所在的所用域有效。
我們舉例來看看下面的代碼。
代碼 1:
console.log(fn);
var fn = 1;
functionfn() {
}
console.log(fn);
相當於:
var fn = undefined;
functionfn() {
}
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;
functionfn() {
a = 2;
console.log(a)
var a = 3;
console.log(a)
}
fn();
console.log(a);
相當於:
var a = undefined;
functionfn() {
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被聲明為變數
functionfn() {// fn被聲明為function,就近原則
}
console.log(fn); //列印結果:function fn(){}
舉例2:
functionfn() {} //fn被聲明為function,且此時fn已經被賦值,這個值就是function的對象
var fn; //fn已經在上一行被聲明且已經有值, 再 var 無效,並不會重設為 undefined
console.log(fn) //列印結果:function fn(){}既然再var無效,但是再function,是有效:
functionfn() {} //fn被聲明為function,且此時fn已經有值,這個值就是function的對象
functionfn() { //此時fn被重複賦值,會覆蓋上一行的值
console.log('smyhvae');
}
console.log(fn)
列印結果:
函數範圍中的變數提升(兩點提醒)
提醒1:
在函數範圍也有聲明提前的特性:
- 使用var關鍵字聲明的變數,是在函數範圍內有效,而且會在函數中所有的代碼執行之前被聲明
- 函式宣告也會在函數中所有的代碼執行之前執行
因此,在函數中,沒有var聲明的變數都會成為全域變數,而且並不會提前聲明。
舉例1:
var a = 1;
functionfoo() {
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定義的變數,是在塊級範圍內有效。
本文永久更新連結地址:https://www.bkjia.com/Linux/2018-03/151490.htm