變量提升
原理:JS引擎的工作方式是先解析代碼倘待,獲取所有被聲明的變量软啼;然后在運(yùn)行。JS代碼自上而下執(zhí)行之前延柠,瀏覽器首先會(huì)把所有帶 “VAR”/“FUNCTION” 關(guān)鍵詞的進(jìn)行提前 “聲明” 或者 “定義” 祸挪,這種預(yù)先處理機(jī)制稱之為 “變量提升”。
console.log(a, b);//undefined undefined
var a = 12,
b = 12;
function fn() {
console.log(a, b);//=>undefined 12
var a = b = 13;
console.log(a, b);//=>13 13
}
fn();
console.log(a, b);//=>12 13
- undefined undefined:首先輸出這個(gè)結(jié)果是因?yàn)樽兞刻嵘昙洌辞叭凶兂?/li>
var a;
var b;
console.log(a,b);//undefined undefined
a = 12;
b = 12;
- undefined 12:接下來執(zhí)行函數(shù)fn(fn一開始也被執(zhí)行了變量提升,只不過函數(shù)中存儲(chǔ)的都是字符串而已)贿条,對(duì)fn內(nèi)部進(jìn)行分析,即內(nèi)部代碼變成:
var a;
console.log(a,b);//undefined 12
a = 13;
b = 13; //不加var的本質(zhì)是WIN的屬性增热,即相當(dāng)于window.b = 13;
console.log(a,b);//13 13
一開始b在fn內(nèi)部找不到整以,便會(huì)開始往上一層找,找到了全局的b峻仇,于是b輸出12公黑。
當(dāng)經(jīng)過var a = b = 13; 后,b被賦值為13摄咆,于是輸出先從函數(shù)內(nèi)部找b凡蚜,找到了b=13,第二次輸出b為13吭从。(朝蜘!同時(shí),最先定義的全局變量b = 12也被賦值為13涩金,故最后的b也等于13)
私有作用域中帶var和不帶var的區(qū)別:
- 帶var的在私有作用于變量提升階段谱醇,都聲明為私有變量,和外界沒有任何的關(guān)系
- 不帶var不是私有變量步做,會(huì)向它的上級(jí)作用于查找副渴,一直找到window為止(這種查找機(jī)制叫做:“作用域鏈”),也就是在私有作用域中操作的這個(gè)非私有變量全度,是一直操作別人的
只對(duì)等號(hào)左邊進(jìn)行變量提升
sum();
fn();// Uncaught TypeError: fn is not a function
//=>匿名函數(shù)之函數(shù)表達(dá)式
var fn = function(){
console.log('fn');
}//=>代碼執(zhí)行到此處會(huì)把函數(shù)值賦值給fn
//=>普通的函數(shù)
function sum(){
console.log('sum');
}
條件判斷下的變量提升
/*
* 在當(dāng)前作用域下煮剧,不管條件是否成立都要進(jìn)行變量提升
* =>帶VAR的還是只聲明
* =>帶FUNCTION的在老版本瀏覽器渲染機(jī)制下,聲明和定義都處理,但是為了迎合ES6中的塊級(jí)作用
* 域轿秧,新版瀏覽器對(duì)于函數(shù)(在條件判斷中的函數(shù))中跌,
* 不管條件是否成立,都只是先聲明菇篡,沒有定義漩符,類似于var
*/
console.log(a);//undefined
if(1 === 2){
var a = 3;
}
console.log(a);//undefined
重名問題的處理
fn();//=>4
function fn() {console.log(1);}
fn();//=>4
function fn() {console.log(2);}
fn();//=>4
var fn=100;//=>帶VAR的在提升階段只把聲明處理了,賦值操作沒有處理,所以在代碼執(zhí)行的時(shí)候需要完成賦值 FN=100
fn();//=>100() Uncaught TypeError: fn is not a function
function fn() {console.log(3);}
fn();
function fn() {console.log(4);}
fn();
帶VAR和FUNCTION關(guān)鍵字聲明相同的名字,這種也算是重名了(其實(shí)是一個(gè)FN驱还,只是存儲(chǔ)值的類型不一樣)
關(guān)于重名的處理:如果名字重復(fù)了嗜暴,不會(huì)重新的聲明,但是會(huì)重新的定義(重新賦值)[不管是變量提升還是代碼執(zhí)行階段皆是如此]