1. 程式人生 > >JavaScript函數(三)——閉包及作用域

JavaScript函數(三)——閉包及作用域

閉包 n) 定義 var 成了 局部變量 val 執行函數 eid

閉包

概念

只有函數內部的子函數才能讀取局部變量,所以閉包可以理解成“定義在一個函數內部的函數“。在本質上,閉包是將函數內部和函數外部連接起來的橋梁

例子

function outer(){
    var localVal = 30;
    return localVal;
}

outer();//30

function outer(){
    var localVal = 30;
    return function() {
        return localVal;
    }
}

var func = outer();
func();//30

作用:比如在一個函數中嵌套一個函數,通過閉包可以讓嵌套函數訪問到包裹它的函數的局部變量。

封裝

(function(){
    var _userId = 123;
    var _typeId = ‘item‘;
    var export = {};
    
    function converter(userId){
        return + userId;
    }
    
    export.getUserId = function(){
        return converter(_userId);
    }
    
    export.getTypeId = function(){
        return _typeId;
    }
    window.export = export;
})();

export.getUserId();//123
export.getTypeId();//item

export._uerId;//undefined
export._typeId;//undefined
export.converter;//undefined

閉包陷阱

var tasks = [];

for (var i=0; i<3; i++) {
    tasks.push(function() {
        console.log(‘>>> ‘ + i);
    });
}

console.log(‘end for.‘);

for (var j=0; j<tasks.length; j++) {
    tasks[j]();
}

輸出結果都為3。這個問題的原因在於,函數創建時並未執行,所以先打印end for.,然後才執行函數,由於函數引用了循環變量i,而i的作用域是整個函數,而不是循環,在函數執行時,i的值已經變成了3。

解決方法
再創建一個函數,將循環變量作為函數參數傳入:

var tasks = [];

for (var i=0; i<3; i++) {
    var fn = function(n) {
        tasks.push(function() {
            console.log(‘>>> ‘ + n);
        });
    };
    fn(i);
}

//簡化語法,直接用匿名函數的立即執行模式(function() { ... })()

var tasks = [];

for (var i=0; i<3; i++) {
    (function(n) {
       tasks.push(function() {
           console.log(‘>>> ‘ + n);
        });
    })(i);
}

總結

優點:靈活方便,封裝
缺點:空間浪費,內存泄漏,性能消耗

JavaScript函數(三)——閉包及作用域