JavaScript 作用域相關(guān)

隨手刷SF,看到一篇譯文《你想知道的關(guān)于 JavaScript 作用域的一切》,著實(shí)寫(xiě)得不錯(cuò),推薦給各位小伙伴看看。

現(xiàn)在組內(nèi)的很多Presenter是通過(guò)這種私有作用域+公開(kāi)接口的方式實(shí)現(xiàn)的,讀過(guò)此文應(yīng)該能夠有進(jìn)一步的了解。

不過(guò),有一點(diǎn)點(diǎn)小細(xì)節(jié)需要補(bǔ)充,那就是JS的變量提升函數(shù)提升。

這篇在函數(shù)作用域一節(jié)中提及:

JavaScript中所有的作用域在創(chuàng)建的時(shí)候都只伴隨著函數(shù)作用域,循環(huán)語(yǔ)句像for或者while、條件語(yǔ)句像if或者switch都不能夠產(chǎn)生新的作用域。新的函數(shù) = 新的作用域 這就是規(guī)則。

試試看執(zhí)行這段代碼:

for (var i = 0; i < 5; i++) { }
console.log(i);

如果在C++、 Java等語(yǔ)言中,這里連編譯都通不過(guò),因?yàn)檫@里構(gòu)造了一個(gè)塊作用域,變量i僅在這個(gè)for循環(huán)中生效。
但在JS中,卻可以得到i的值,這是為什么呢?

變量聲明提升

實(shí)際上,在JS中,聲明語(yǔ)句會(huì)被自動(dòng)提升到該函數(shù)或變量所在區(qū)域的最頂部。例如:

console.log(x); // undefined
var x = 3;
console.log(x); // 3

在執(zhí)行的時(shí)候,它實(shí)際上被解釋成了:

var x;
console.log(x); // undefined
x = 3;
console.log(x); // 3

x變量的聲明被提升了,賦值語(yǔ)句仍停留在原處,因此第一次能夠打印出x是個(gè)undefined,第二次才會(huì)打出x的值。

因此,如果需要重復(fù)初始化變量,一定要顯式聲明它的初始值,而不能只靠var語(yǔ)句,否則就會(huì)出現(xiàn)問(wèn)題:

var x;
x = 3;
console.log(x); // 3
var x;
console.log(x); // 3

這段代碼執(zhí)行時(shí),兩句x的聲明都被提到了最前,因此第二次依然能夠打印出原先的值:

var x;
var x;
x = 3;
console.log(x); // 3
console.log(x); // 3

函數(shù)聲明提升

對(duì)于函數(shù)的聲明,JS也會(huì)進(jìn)行提前,但這僅限于以function funName()方式聲明的函數(shù)。例如:

console.log(typeof fun); // undefined
fun(); // TypeError: undefined is not a function
var fun = function() { console.log("success"); };
console.log(typeof fun); // function
fun(); // success;

console.log(typeof fun2); // function
fun2(); ?// success
function fun2() { console.log("success"); }

console.log(typeof fun3); // undefined
fun3(); // TypeError: undefined is not a function
console.log(typeof fun4); // undefined
fun4(); // TypeError: undefined is not a function
var fun3 = function fun4() { console.log("success"); };
console.log(typeof fun3); // function
fun3(); // success
console.log(typeof fun4); // undefined
fun4(); // TypeError: undefined is not a function

聲明的優(yōu)先級(jí)

JS中變量是動(dòng)態(tài)類(lèi)型的,那如果一個(gè)變量名先后被聲明為函數(shù)或?qū)ο髸r(shí),哪個(gè)更優(yōu)先呢?

var x, y, z;
console.log(typeof x); // function
console.log(typeof y); // function
console.log(typeof z); // function

function x() {};
x = 3;
console.log(typeof x); // number

y = 5;
console.log(typeof y); // number
function y() {};

z = {};
console.log(typeof z); // object
function z() {};

運(yùn)行上述代碼可以發(fā)現(xiàn),函數(shù)的聲明優(yōu)先級(jí)總是高于變量的聲明,不論代碼中的順序如何。這可能引發(fā)一個(gè)有趣的現(xiàn)象:

var x = 10;
function x() {};
x(); // TypeError: number is not a function

因?yàn)閳?zhí)行時(shí)變成了這樣:

function x() {};
var x;
x = 10;
x();?

函數(shù)聲明和變量聲明都提前了,初始化的位置卻沒(méi)有變!是不是很神奇……請(qǐng)大家好好遵循命名規(guī)范,不要寫(xiě)出這樣糾結(jié)的代碼喔……

變量的優(yōu)先級(jí)

說(shuō)完了聲明,我們來(lái)說(shuō)說(shuō)取值的優(yōu)先級(jí)。直接跑代碼吧:

var a = 3, b = 5, c = 8, d = 9;
console.log(typeof a, b, c, d); // number 5 8 9
function fn(a, b, c){
? ? console.log(typeof a, b, c, d); // function 2 undefined 9
? ? function a(){};
? ? var b = 10;
}
fn(1, 2);

高下立見(jiàn):函數(shù)局域變量>形參>全局變量。

以上,僅作為一點(diǎn)小小的補(bǔ)充,希望大家在開(kāi)發(fā)過(guò)程中多多留意,不要掉到坑里去喔……

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容