js進(jìn)階語法之變量提升、函數(shù)提升以及參數(shù)的命名沖突問題解決
前言
預(yù)處理階段:js在編譯代碼時(shí)有一個(gè)預(yù)處理階段,這個(gè)過程會(huì)將原本的代碼進(jìn)行分割處理;
源程序 ---> 預(yù)處理塊+ 剩余代碼塊
預(yù)處理塊中的代碼會(huì)優(yōu)先于剩余代碼塊中的代碼執(zhí)行
什么是變量提升,函數(shù)提升
變量提升:當(dāng)聲明一個(gè)變量時(shí),這個(gè)聲明過程會(huì)被預(yù)處理機(jī)制塞入到預(yù)處理塊中優(yōu)先執(zhí)行,這就是變量提升,使用var定義的變量擁有變量提升
函數(shù)提升:當(dāng)聲明一個(gè)函數(shù)時(shí),這個(gè)聲明過程會(huì)被預(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;
以上的代碼會(huì)產(chǎn)生變量提升,它等價(jià)于下面的代碼,
{// 模擬預(yù)處理塊
var a;
}
// 正常執(zhí)行的剩余代碼塊
console.log(a); // undefined
a = 1;因?yàn)樽兞刻嵘木壒剩琣會(huì)在打印執(zhí)行前被聲明,所以會(huì)打印成undefined
函數(shù)提升
函數(shù)提升,將函數(shù)體放入預(yù)編譯的詞法環(huán)境 function b(){}
console.log(b);
function b(){
console.log('b')
};以上的代碼會(huì)產(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í)在場(chǎng)的優(yōu)先級(jí)
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會(huì)打印成undefined
2.優(yōu)先級(jí)判斷
console.log(b);
var b = function(){
console.log('b1')
};
function b(){
console.log('b2')
};
console.log(b);函數(shù)提升的優(yōu)先級(jí)是比變量提升的優(yōu)先級(jí)大的,當(dāng)出現(xiàn)聲明同名的變量和函數(shù)時(shí),在預(yù)處理塊中最終都會(huì)變成函數(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)先級(jí)的理解方式,還有下面這種,將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)先級(jí)判斷
同名參數(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ù)會(huì)在預(yù)處理中聲明后賦值給同名變量,foo不為undefined,后面的賦值就不會(huì)變成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ù)會(huì)在函數(shù)提升的前面(函數(shù)體賦值的前面),導(dǎo)致傳入的參數(shù)被覆蓋
總結(jié)
所以可以得出同名參數(shù)名,變量名,函數(shù)名的預(yù)處理順序?yàn)椋?/p>
變量提升---參數(shù)傳遞---函數(shù)提升 (聲明函數(shù)名---變量提升---參數(shù)傳遞---函數(shù)體賦值)
所以最終這個(gè)名稱會(huì)被函數(shù)奪取,這就是函數(shù)提升優(yōu)先級(jí)最高的原因
完整代碼和運(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)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
javascript下4個(gè)跨瀏覽器必備的函數(shù)
如果你的項(xiàng)目要用到 JavaScript,而你不使用任何 JavaScript 框架,那么對(duì)于那些常用且各個(gè)瀏覽器明顯不同的地方就需要用函數(shù)來封裝起來。2010-03-03
微信小程序如何實(shí)現(xiàn)商品列表跳轉(zhuǎn)商品詳情頁功能
最近在學(xué)微信小程序開發(fā)的時(shí)候,碰上了一個(gè)問題,所以想著總結(jié)下,這篇文章主要給大家介紹了關(guān)于微信小程序如何實(shí)現(xiàn)商品列表跳轉(zhuǎn)商品詳情頁功能的相關(guān)資料,需要的朋友可以參考下2022-04-04
JavaScript可折疊區(qū)域?qū)崿F(xiàn)代碼
可折疊區(qū)域的基本思想:通過點(diǎn)擊某個(gè)地方來顯示或隱藏屏幕中的某個(gè)區(qū)域。2010-10-10
BootStrap與validator 使用筆記(JAVA SpringMVC實(shí)現(xiàn))
這篇文章主要介紹了BootStrap與validator 使用筆記(JAVA SpringMVC實(shí)現(xiàn))的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-09-09

