自認(rèn)為對(duì)變量提升有一定的了解,其實(shí)不然。
概念
什么是變量提升
變量提升换淆,在當(dāng)前上下文中(全局/私有/塊級(jí)),js 代碼自上而下執(zhí)行之前几颜,瀏覽器會(huì)提前處理一些事情(可以理解為詞法解析的一個(gè)環(huán)節(jié),詞法解析一定發(fā)生在代碼執(zhí)行之前)
變量提升會(huì)把上下文中的所有帶 var/function 關(guān)鍵字進(jìn)行提前聲明或者定義
var a = 10
聲明 declare var a;
定義 defined a=10
帶 var 的只會(huì)提前聲明
帶 function 會(huì)提前聲明和定義
看看 var 的變量提升
// 代碼執(zhí)行之前讯屈,全局上下文中的變量會(huì)提升
// var a;默認(rèn)是undefined
console.log(a); // undefined
var a = 12; // 執(zhí)行到這才會(huì)給 a賦值 12(不需要聲明a了蛋哭,變量提升階段完成了,完成的事情不會(huì)重新處理)
a = 13; // 全局變量 a=13
console.log(a); // 13
看看 function 的變量提升
/*
全局上下文中的變量提升
fn = 函數(shù) 這個(gè)階段函數(shù)的聲明和賦值都做了涮母,所以 調(diào)用fn()可以在函數(shù)代碼之前調(diào)用
*/
fn();
function fn() {
var a = 12;
console.log("ok");
}
fn(); // 會(huì)報(bào)錯(cuò) TypeError: fn is not a function谆趾,因?yàn)橛胿ar 聲明的變量只會(huì)聲明fn但是不會(huì)賦值
var fn = function () {
var a = 12;
console.log("ok");
};
var fn = function fb() {
// 原本匿名函數(shù)給具名化以后,但是在外部依然是不能方位的叛本,在當(dāng)前上下文中是不會(huì)創(chuàng)建這個(gè)名字沪蓬,但是在函數(shù)內(nèi)部我們是可以調(diào)用這個(gè)函數(shù)名,因?yàn)椋涸诤瘮?shù)執(zhí)行時(shí)来候,在形成私有上下文中跷叉,會(huì)把這個(gè)具名化的名字作為私有上下文中的變量來(lái)處理
var a = 12;
console.log("ok");
fb(); // 遞歸調(diào)用
};
fb(); // 會(huì)報(bào)錯(cuò)Uncaught ReferenceError: fb is not defined
fn();
ES6
全局的變量提升 只有 var 和 function ,而 let 和 const 是不會(huì)有變量提升的
console.log(a); // 會(huì)報(bào)錯(cuò)Uncaught ReferenceError: a is not defined
let a = 1;
window
var 或者 function 在全局上下文聲明的變量會(huì)映射到全局對(duì)象中(window),作為他的屬性,修改每個(gè)屬性,全局對(duì)象中對(duì)應(yīng)的屬性也會(huì)修改
var a = 13;
console.log(window.a); // 13
條件判斷
全局上下文中的變量提升:不論條件是否判斷成立云挟,都需要進(jìn)行變量提升(條件中帶 function 在新版本瀏覽器中只會(huì)提前聲明梆砸,不會(huì)提前賦值)
老版本:
var a;
fn = 函數(shù)
新版本:
var a
fn
console.log(a, fn); // undefined undefined
// 首先不用看條件是否成立,會(huì)先進(jìn)行變量提升园欣,此時(shí)a:undefined ,并且window 也會(huì)有a
// 所以 "a" in window 為true 取反 為false
if (!("a" in window)) {
var a = 1;
function fn() {}
}
console.log(a); // undefined
面試題
fn();
function fn() {
console.log(1);
}
fn();
function fn() {
console.log(2);
}
fn();
var fn = function () {
console.log(3);
};
fn();
function fn() {
console.log(4);
}
fn();
function fn() {
console.log(5);
}
fn()
分析過(guò)程:
1.首先需要變量提升
聲明 fn 并賦值函數(shù) 1 已經(jīng)聲明過(guò)的不需要重復(fù)聲明,只需要重新賦值即可
fn=>1
=>2
var fn
=> 4
=> 5
開(kāi)始指向 fn
fn() 5
fn() 5
fn() 5
把 fn(){console.log(3)} 賦值給 fn
fn() 3
fn() 3
fn() 3
所以結(jié)果就是 5 5 5 3 3 3
var foo = 1;
function bar() {
if (!foo) {
var foo = 10;
}
console.log(foo);
}
bar();
執(zhí)行函數(shù) bar ,會(huì)進(jìn)行變量提升帖世,因?yàn)椴徽摋l件是否成立都需要變量提升,
所以函數(shù)內(nèi) foo 會(huì)變量提升為 undefined