欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

JavaScript函数(三)——闭包及作用域

程序员文章站 2022-03-31 17:07:34
闭包 概念 只有函数内部的子函数才能读取局部变量,所以闭包可以理解成“定义在一个函数内部的函数“。在本质上,闭包是将函数内部和函数外部连接起来的桥梁 例子 作用:比如在一个函数中嵌套一个函数,通过闭包可以让嵌套函数访问到包裹它的函数的局部变量。 封装 闭包陷阱 总结 优点:灵活方便,封装 缺点:空间 ......

闭包

概念

只有函数内部的子函数才能读取局部变量,所以闭包可以理解成“定义在一个函数内部的函数“。在本质上,闭包是将函数内部和函数外部连接起来的桥梁

例子

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);
}

总结

优点:灵活方便,封装
缺点:空间浪费,内存泄漏,性能消耗