js進(jìn)階語法之變量提升、函數(shù)提升以及參數(shù)的命名沖突問題解決
前言
預(yù)處理階段:js在編譯代碼時(shí)有一個(gè)預(yù)處理階段,這個(gè)過程會將原本的代碼進(jìn)行分割處理;
源程序 ---> 預(yù)處理塊+ 剩余代碼塊
預(yù)處理塊中的代碼會優(yōu)先于剩余代碼塊中的代碼執(zhí)行
什么是變量提升,函數(shù)提升
變量提升:當(dāng)聲明一個(gè)變量時(shí),這個(gè)聲明過程會被預(yù)處理機(jī)制塞入到預(yù)處理塊中優(yōu)先執(zhí)行,這就是變量提升,使用var定義的變量擁有變量提升
函數(shù)提升:當(dāng)聲明一個(gè)函數(shù)時(shí),這個(gè)聲明過程會被預(yù)處理機(jī)制塞入到預(yù)處理塊中優(yōu)先執(zhí)行,這就是函數(shù)提升,使用function定義的函數(shù)擁有函數(shù)提升
提升的判斷:當(dāng)一個(gè)變量和函數(shù)在正常的順序中沒有聲明但被調(diào)用時(shí)就可能產(chǎn)生“提升”
變量提升
變量提升,將變量名放入預(yù)編譯的詞法環(huán)境 var a(undefined)
console.log(a); var a = 1;
以上的代碼會產(chǎn)生變量提升,它等價(jià)于下面的代碼,
{// 模擬預(yù)處理塊 var a; } // 正常執(zhí)行的剩余代碼塊 console.log(a); // undefined a = 1;
因?yàn)樽兞刻嵘木壒?,a會在打印執(zhí)行前被聲明,所以會打印成undefined
函數(shù)提升
函數(shù)提升,將函數(shù)體放入預(yù)編譯的詞法環(huán)境 function b(){}
console.log(b); function b(){ console.log('b') };
以上的代碼會產(chǎn)生函數(shù)提升,它等價(jià)于下面的代碼,
{// 模擬預(yù)處理塊 function b(){ console.log('b') }; } // 正常執(zhí)行的剩余代碼塊 console.log(b);
function聲明的函數(shù)都存在函數(shù)提升,所以可以在聲明函數(shù)之前使用函數(shù)(先寫出函數(shù)的用法,在完成函數(shù)的實(shí)現(xiàn))
關(guān)于變量提升和函數(shù)提升的判斷
了解了基本的變量提升和函數(shù)提升,接下來開始區(qū)分一些二者的區(qū)別和同時(shí)在場的優(yōu)先級
1.變量賦值的函數(shù)
console.log(a); var a = function(){ console.log('a') };
很顯然這是由var聲明的變量,擁有變量提升,只不過它的值是一個(gè)函數(shù)體
{// 模擬預(yù)處理塊 var a; } // 正常執(zhí)行的剩余代碼塊 console.log(a); // undefined a = function(){ console.log('a') };
所以這個(gè)a會打印成undefined
2.優(yōu)先級判斷
console.log(b); var b = function(){ console.log('b1') }; function b(){ console.log('b2') }; console.log(b);
函數(shù)提升的優(yōu)先級是比變量提升的優(yōu)先級大的,當(dāng)出現(xiàn)聲明同名的變量和函數(shù)時(shí),在預(yù)處理塊中最終都會變成函數(shù),
{// 模擬預(yù)處理塊 var b; function b(){ console.log('b2') }; } // 正常執(zhí)行的剩余代碼塊 console.log(b);// 能打印'b2'的函數(shù) b = function(){ console.log('b1') }; console.log(b);// 能打印'b1'的函數(shù)
除了上面這種優(yōu)先級的理解方式,還有下面這種,將function聲明拆成了兩個(gè)部分,先聲明函數(shù)名,在賦值函數(shù)體,而變量的聲明在它們之間
{// 模擬預(yù)處理塊 function b var b; b = function(){ console.log('b2') }; } // 正常執(zhí)行的剩余代碼塊 console.log(b);// 能打印'b2'的函數(shù) b = function(){ console.log('b1') }; console.log(b);// 能打印'b1'的函數(shù)
tips:以上兩種方式的結(jié)果是一樣的,采用哪種分析方式都可以
3.同名參數(shù)名,變量名,函數(shù)名的優(yōu)先級判斷
同名參數(shù)名,變量名的判斷
var foo = 'hello'; (function(foo){ console.log(foo); var foo = foo || 'world'; console.log(foo); })(foo); console.log(foo);
這里只分析了立即執(zhí)行函數(shù)內(nèi)的預(yù)處理
var foo = 'hello'; (function(foo){ // 模擬立即執(zhí)行函數(shù)內(nèi)的預(yù)處理塊 { var foo; foo = foo; //傳入的參數(shù)('hello') } // 正常執(zhí)行的剩余代碼塊 console.log(foo); foo = foo || 'world'; console.log(foo); })(foo); console.log(foo);
所以最后連續(xù)打印了3個(gè)hello,傳入的參數(shù)會在預(yù)處理中聲明后賦值給同名變量,foo不為undefined,后面的賦值就不會變成world
當(dāng)同名參數(shù)名,變量名,函數(shù)名同時(shí)存在
function fn (m){ console.log(m); var m = 1; function m(){ } console.log(m); } fn(10)
同樣有兩種理解方式
function fn (m){ // 模擬預(yù)處理塊 { var m; m = m;// 傳入的參數(shù)(10) function m(){ } }; } // 正常執(zhí)行的剩余代碼塊 console.log(m);// function(){} m = 1; console.log(m);// 1 } fn(10)
function fn (m){ // 模擬預(yù)處理塊 { function m var m; m = m;// 傳入的參數(shù)(10) m = function(){ } }; } // 正常執(zhí)行的剩余代碼塊 console.log(m);// function(){} m = 1; console.log(m);// 1 } fn(10)
可以看到這個(gè)函數(shù)的輸出和傳入的參數(shù)沒有任何關(guān)系,因?yàn)閭魅氲膮?shù)會在函數(shù)提升的前面(函數(shù)體賦值的前面),導(dǎo)致傳入的參數(shù)被覆蓋
總結(jié)
所以可以得出同名參數(shù)名,變量名,函數(shù)名的預(yù)處理順序?yàn)椋?/p>
變量提升---參數(shù)傳遞---函數(shù)提升 (聲明函數(shù)名---變量提升---參數(shù)傳遞---函數(shù)體賦值)
所以最終這個(gè)名稱會被函數(shù)奪取,這就是函數(shù)提升優(yōu)先級最高的原因
完整代碼和運(yùn)行結(jié)果展示
// 變量提升,將變量名放入預(yù)編譯的詞法環(huán)境 var a(undefined) console.log(a); var a = function(){ console.log('a') }; console.log(a); // 函數(shù)提升,將函數(shù)體放入預(yù)編譯的詞法環(huán)境 function b(){} console.log(b); var b = function(){ console.log('b1') }; function b(){ console.log('b2') }; console.log(b); // function b 函數(shù)名提升 // var b 變量名提升 // b = (){} 函數(shù)體初始化 // 因?yàn)楹瘮?shù)體初始化總在變量名之后,所以每次都是優(yōu)先預(yù)編譯成函數(shù) // 結(jié)合自執(zhí)行函數(shù) var foo = 'hello'; (function(foo){ console.log(foo); var foo = foo || 'world'; console.log(foo); })(foo); console.log(foo); // 依次輸出 hello hello hello // 預(yù)編譯后 var foo = 'hello'; (function (foo) { var foo; // undefined; foo= 'hello'; //傳入的foo的值 console.log(foo); // hello foo = foo || 'world';// 因?yàn)閒oo有值所以沒有賦值world console.log(foo); //hello })(foo); console.log(foo);// hello,打印的是var foo = 'hello' 的值(變量作用域) // function m(){ // console.log('m'); // }; // var m; // m =1; // function m(){ // } // console.log(m) function fn (m){ console.log(m); var m = 1; function m(){ } console.log(m); } fn(10) // function m // var m // 參數(shù)m // m = (){} // m = 1 // function > parmas > var
到此這篇關(guān)于js進(jìn)階語法之變量提升、函數(shù)提升以及參數(shù)的命名沖突問題解決的文章就介紹到這了,更多相關(guān)js變量、函數(shù)提升及參數(shù)命名沖突內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
echartjs實(shí)現(xiàn)cross十星輔助線實(shí)現(xiàn)示例詳解
這篇文章主要為大家介紹了echartjs實(shí)現(xiàn)cross十星輔助線實(shí)現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12JS實(shí)現(xiàn)網(wǎng)頁搶購功能(觸發(fā),終止腳本)
小編通過一個(gè)網(wǎng)頁式的搶購功能的實(shí)現(xiàn)給大家講解一下JS如何觸發(fā)和終止腳本來完成這個(gè)任務(wù)。2017-11-11JavaScript使用Broadcast?Channel實(shí)現(xiàn)前端跨標(biāo)簽頁通信
這篇文章主要為大家詳細(xì)介紹了JavaScript如何使用Broadcast?Channel實(shí)現(xiàn)前端跨標(biāo)簽頁通信,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-04-04JavaScript對象學(xué)習(xí)小結(jié)
JavaScript 中的所有事物都是對象:字符串、數(shù)值、數(shù)組、函數(shù).幾乎用到的每個(gè)js都離不開它的js對象。此外,JavaScript 允許自定義對象,下面跟著小編學(xué)習(xí)javascript對象學(xué)習(xí)小結(jié),需要的朋友可以參考下2015-09-09BootstrapTable refresh 方法使用實(shí)例簡單介紹
本文就bootstrapTable refresh 方法如何傳遞參數(shù)做簡單舉例說明,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友參考下吧2017-02-02