JavaScript——可變范圍和關(guān)閉

在JavaScript中,您在使用變量之前先聲明它們:var

> var x;

> x

未定義

> y

ReferenceError:y未定義

您可以使用一個(gè)var 語(yǔ)句來(lái)聲明和初始化幾個(gè)變量:

var x = 1, y = 2, z = 3;

但是我建議每個(gè)變量使用一個(gè)語(yǔ)句(原因在Syntax中進(jìn)行了解釋)。因此,我將前面的語(yǔ)句重寫為:

var x = 1;

var y = 2;

var z = 3;

由于提升(請(qǐng)參見(jiàn)變量提升),通常最好在函數(shù)的開(kāi)頭聲明變量。

變量是函數(shù)范圍的

變量的范圍始終是完整的功能(與當(dāng)前塊相反)。例如:

function foo() {

? ? var x = -512;

? ? if (x < 0) {? // (1)

? ? ? ? var tmp = -x;

? ? ? ? ...

? ? }

? ? console.log(tmp);? // 512

}

我們可以看到變量tmp不限于從第(1)行開(kāi)始的塊。它存在直到函數(shù)結(jié)束。

變量被吊起

每個(gè)變量聲明都是懸掛的:該聲明將移至該函數(shù)的開(kāi)頭,但保留的賦值將保留。例如,請(qǐng)考慮以下函數(shù)中第(1)行中的變量聲明:

function foo() {

? ? console.log(tmp); // undefined

? ? if (false) {

? ? ? ? var tmp = 3;? // (1)

? ? }

}

在內(nèi)部,前面的函數(shù)是這樣執(zhí)行的:

function foo() {

? ? var tmp;? // hoisted declaration

? ? console.log(tmp);

? ? if (false) {

? ? ? ? tmp = 3;? // assignment stays put

? ? }

}

關(guān)閉

每個(gè)功能 即使它離開(kāi)了創(chuàng)建它的作用域,它仍然與圍繞它的函數(shù)的變量保持聯(lián)系。例如:

function createIncrementor(start) {

? ? return function () {? // (1)

? ? ? ? start++;

? ? ? ? return start;

? ? }

}

從第(1)行開(kāi)始的函數(shù)會(huì)離開(kāi)其創(chuàng)建時(shí)所在的上下文,但仍保持與以下版本的實(shí)時(shí)連接start:

> var inc = createIncrementor(5);

> inc()

6

> inc()

7

> inc()

8

一個(gè)封閉的功能加上其周邊范圍的變量的連接。因此,createIncrementor()返回的是封閉。

IIFE模式:引入新的范圍

有時(shí)您想引入一個(gè)新的 變量作用域-例如,防止變量成為全局變量。在JavaScript中,您不能使用塊來(lái)這樣做。您必須使用一個(gè)函數(shù)。但是,存在一種以塊狀方式使用功能的模式。它稱為IIFE(立即調(diào)用的函數(shù)表達(dá)式,發(fā)音為“ iffy”):

(function () {? // open IIFE

? ? var tmp = ...;? // not a global variable

}());? // close IIFE

確保完全按照顯示的方式鍵入前面的示例(注釋除外)。IIFE是定義后立即調(diào)用的函數(shù)表達(dá)式。在函數(shù)內(nèi)部,存在新的作用域,以防止其tmp成為全局變量。有關(guān)IIFE的詳細(xì)信息,請(qǐng)咨詢通過(guò)IIFE引入新范圍。

IIFE用例:通過(guò)關(guān)閉無(wú)意間共享

閉包保持它們與外部變量的連接,有時(shí)這不是您想要的:

var result = [];

for (var i=0; i < 5; i++) {

? ? result.push(function () { return i });? // (1)

}

console.log(result[1]()); // 5 (not 1)

console.log(result[3]()); // 5 (not 3)

第(1)行中返回的值始終是的當(dāng)前值i,而不是創(chuàng)建函數(shù)時(shí)的值。循環(huán)完成后,i值為5,這就是數(shù)組中所有函數(shù)都返回該值的原因。如果希望第(1)行中的函數(shù)接收的當(dāng)前值的快照,則i可以使用IIFE:

for (var i=0; i < 5; i++) {

? ? (function () {

? ? ? ? var i2 = i; // copy current i

? ? ? ? result.push(function () { return i2 });

? ? }());

}

?著作權(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)容