99re热这里只有精品视频,7777色鬼xxxx欧美色妇,国产成人精品一区二三区在线观看,内射爽无广熟女亚洲,精品人妻av一区二区三区

變量作用域和閉包(Variable scoping and closures)

2018-06-15 18:48 更新

在JavaScript中,你必須使用變量之前,通過var聲明變量:

> var x;
> x = 3;
> y = 4;
ReferenceError: y is not defined

你可以用一條var語句聲明和初始化多個(gè)變量:

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

但我建議每個(gè)變量使用一條語句。因此,我將上面的語句重寫為:

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

由于提升(見下文),最好在函數(shù)頂部聲明變量。

變量和函數(shù)作用域(Variables are function-scoped)

變量的作用域總是整個(gè)函數(shù)(沒有塊級(jí)作用域)。例如:

function foo() {
    var x = -3;
    if (x < 0) {  // (*)
        var tmp = -x;
        ...
    }
    console.log(tmp);  // 3
}

我們可以看到tmp變量不僅在(*)所在行的語句塊存在,它在整個(gè)函數(shù)內(nèi)都存在。

變量提升(Variables are hoisted)

變量聲明會(huì)被提升:聲明會(huì)被移到函數(shù)的頂部,但賦值過程不會(huì)。舉個(gè)例子,在下面的函數(shù)中(*)行位置聲明了一個(gè)變量。

function foo() {
    console.log(tmp); // undefined
    if (false) {
        var tmp = 3;  // (*)
    }
}

在內(nèi)部,上面的函數(shù)被執(zhí)行像下面這樣:

function foo() {
    var tmp;  // declaration is hoisted
    console.log(tmp);
    if (false) {
        tmp = 3;  // assignment stays put
    }
}

閉包(Closures)

每個(gè)函數(shù)保持和函數(shù)體內(nèi)部變量的連接,甚至離開創(chuàng)建它的作用域之后。例如:

function createIncrementor(start) {
    return function () {  // (*)
        return start++;
    }
}

在(*)行開始的函數(shù)在它創(chuàng)建時(shí)保留上下文,并在內(nèi)部保存一個(gè)start活動(dòng)值:

> var inc = createIncrementor(5);
> inc()
5
> inc()
6
> inc()
7

閉包是一個(gè)函數(shù)加上和其作用域鏈的鏈接。因此,createIncrementor() 返回的是一個(gè)閉包。

IIFE:模擬塊級(jí)作用域(IIFE: Simulating block scoping)

有時(shí)你想模擬一個(gè)塊,例如你想將變量從全局作用域隔離。完成這個(gè)工作的模式叫做 IIFE(立即執(zhí)行函數(shù)表達(dá)式(Immediately Invoked Function Expression)):

(function () {  // 塊開始
    var tmp = ...;  // 非全局變量
}());  // 塊結(jié)束

上面你會(huì)看到函數(shù)表達(dá)式被立即執(zhí)行。外面的括號(hào)用來阻止它被解析成函數(shù)聲明;只有函數(shù)表達(dá)式能被立即調(diào)用。函數(shù)體產(chǎn)生一個(gè)新的作用域并使 tmp 變?yōu)榫植孔兞俊?/p>

閉包實(shí)現(xiàn)變量共享(Inadvertent sharing via closures)

下面是個(gè)經(jīng)典問題,如果你不知道,會(huì)讓你費(fèi)盡思量。因此,先瀏覽下,對(duì)問題有個(gè)大概的了解。 閉包保持和外部變量的連接,有時(shí)可能和你想像的行為不一致:

var result = [];
for (var i=0; i < 5; i++) {
    result.push(function () { return i });  // (*)
}
console.log(result[1]()); // 5 (不是 1)
console.log(result[3]()); // 5 (不是 3)

(*)行的返回值總是當(dāng)前的i值,而不是當(dāng)函數(shù)被創(chuàng)建時(shí)的i值。當(dāng)循環(huán)結(jié)束后,i的值是5,這是為什么數(shù)組中的所有函數(shù)的返回值總是一樣的。如果你想捕獲當(dāng)前變量的快照,你可以使用 IIFE:

for (var i=0; i < 5; i++) {
    (function (i2) {
        result.push(function () { return i2 });
    }(i));  // 復(fù)制當(dāng)前的i
}

深入閱讀

以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)