閉包和變量提升


關(guān)于閉包的3要點(diǎn)

1 js允許引用函數(shù)外部的變量
2 函數(shù)能夠引用外部函數(shù),即使函數(shù)已經(jīng)返回,一個(gè)函數(shù)能夠引用任何作用域內(nèi)的變量,包括參數(shù)和函數(shù)外部的變量

function sandwichMaker(ingredient) {
    return function(filling) {
        console.log(ingredient + " and " + filling);
    };
}
var make = sandwichMaker("apple");
make("butter"); // "appele and butter"
// 內(nèi)部返回的匿名函數(shù)可以訪問(wèn)sandwichMaker中參數(shù),即使sandwichMaker已經(jīng)return了
// javascript中function是firs-class citizen, 意味著函數(shù)可以作為參數(shù)或者返回值

3 閉包能夠更新外部變量的值,實(shí)際上閉包是通過(guò)引用的方式來(lái)與外部變量建立聯(lián)系,而不是拷貝外部變量的值

function box() {
    var val = undefined;
    return {
        get: function() { return val; },
        set: function(newVal) { val = newVal;},
        type: function() { typeof val; }
    };
}
var b = box();
b.type(); // undefined
b.set("hello");
b.get(); // "hello"
b.type(); // "string"

變量提升(Hoisting)

ES5之前,javascript是沒(méi)有塊級(jí)作用域的,所有的變量都是通過(guò)<b><i>var</i></b> 來(lái)聲明,ES6引入<b><i>let</i></b> 關(guān)鍵字,并引入塊級(jí)作用域的概念.

1.隱式提升變量聲明位置,在var聲明處賦值

function f() {                            function f() {
    // ...                                     var x;  // 提升到此處聲明
   // ...                                      // ...
    {                                       {
        var x = 15;     =>實(shí)際上                x = 15 // 此處賦值
        // ....                                // ...
    }                                      }
}                                         }

使用函數(shù)表達(dá)式時(shí)注意,只有變量提升

hello();
function hello() { // 函數(shù)statement
  console.log('hello')
}

great();

var great = function() { // 函數(shù)表達(dá)式
  console.log('great')
}

// 運(yùn)行結(jié)果
‘hello’
Reference Error

報(bào)錯(cuò)的原因在于, var great 中 只有變量 'great' 提升,而匿名函數(shù)并沒(méi)有提升

let塊級(jí)作用域, 變量不再隱式提升


常見(jiàn)陷阱

function wrapElements(a) {
    var result = [];
    for (var i = 0, n < a.length; i < n; i++) {
        resule[i] = function() { return a[i]; };
    }
    return result;
}

var wrapped = wrapElements([10, 20, 30]);
wrapped[0](); // ?

看起來(lái)沒(méi)什么問(wèn)題,應(yīng)該返回10, 但是實(shí)際上返回undefined,函數(shù)wrapElements綁定3個(gè)局部變量<b>i, n, result</b>,在調(diào)用wrapElements函數(shù)時(shí)在內(nèi)存中為每一個(gè)變量分配一個(gè)"槽點(diǎn)"(slot)用來(lái)存儲(chǔ)變量所賦的值,每次循環(huán)時(shí),內(nèi)部匿名函數(shù)形成一個(gè)<b>閉包</b>,引用<b>i</b>,我們期望的是 i 的值每次循環(huán)匿名函數(shù)都能夠存儲(chǔ) i 的值,實(shí)際上i是引用值,每次循環(huán)之后都會(huì)改變,內(nèi)部函數(shù)最終存儲(chǔ)的是i最后的值,關(guān)鍵點(diǎn)在于: <b>Closure store their outer variables by reference, not by value</b>.
更改方法:

// 1.使用IIEF模擬塊級(jí)作用域,立即執(zhí)行每一次內(nèi)部函數(shù)的調(diào)用
function wrapElements(a) {
    var result = [];
    for (var i = 0, n < a.length; i < n; i++) {
        (function(j) {
             resule[i] = function() { return a[j]; };
        })(i)
       
    }
    return result;
}

// 2.使用ES6 let 關(guān)鍵詞創(chuàng)建塊級(jí)作用域
function wrapElements(a) {
    var result = [];
    for (let i = 0, n < a.length; i < n; i++) {
        resule[i] = function() { return a[i]; };
    }
    return result;
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容