面试题:讲讲你对闭包的理解?有什么优缺点

面试题:讲讲你对闭包的理解?有什么优缺点?

对闭包的理解

从 JS 作用域链的角度出发,函数外部无法访问到函数中的变量,但函数内部可以访问到其外部的变量。所谓闭包(closure),是一种在函数外部访问函数内部变量的一种方式。通常通过在函数中返回一个新函数的方式实现闭包,这个新函数中可以访问到返回它的函数中的所有执行上下文。

词法作用域:创建闭包时所在的作用域

对于以下示例,A 函数返回了 B 函数,此时 B 函数中可以访问到 A 函数中的所有执行上下文(变量等),将返回的 B 函数赋给一个变量,此时在 A 函数外也可以访问到 A 函数中定义的变量(包括为了得到 B 函数传给 A 函数的参数)。

function A(n){
    function B(){
        n++;
        console.log(`n=${n}`)
    }
    return B;
}

let x = A(0);
x(); // n=1
x(); // n=1

通过以上示例,我们也可以认为闭包就是能读取其他函数内部变量的函数

闭包的优缺点

优点

  1. 数据封装:闭包可以将数据封装起来,并通过特定接口向外暴露

    function createCounter() {
        let count = 0; // 封装数据
        return { // 通过返回的闭包对封装数据进行访问和修改
            increment: function() {
                count++;
                return count;
            },
            decrement: function() {
                count--;
                return count;
            },
            getCount: function() {
                return count;
            }
        };
    }
    
    const counter = createCounter();
    console.log(counter.increment()); // 1
    console.log(counter.increment()); // 2
    console.log(counter.getCount()); // 2
    console.log(counter.decrement()); // 1
    
  2. 减少全局变量:闭包可以减少程序中对全局变量的依赖,从而避免命名冲突和全局命名空间的污染

  3. 函数工厂:闭包可以用来创建函数工厂,根据传入的参数,动态生成不同的函数。

    function powerFactory(exp) {
        return function(base) {
            return Math.pow(base, exp);
        };
    }
    
    const square = powerFactory(2); // 传入指数为 2,则生成平方函数
    const cube = powerFactory(3); // 传入指数 3,则生成立方函数
    
    console.log(square(4)); // 输出 16
    console.log(cube(2)); // 输出 8
    
  4. 惰性计算(一种缓存实现):闭包可以用于惰性计算,即在有需要的时候才计算值,从而提高性能。这也可以理解为缓存的一种实现方式,某些值在第一次访问时计算并缓存,之后访问时直接返回缓存的值。

    function lazyValue(fn) {
        let cachedValue;
        return function() {
            if (cachedValue === undefined) {
                cachedValue = fn();
            }
            return cachedValue;
        };
    }
    
    const getValue = lazyValue(() => {
        console.log("Computing value...");
        return 42;
    });
    
    console.log(getValue()); // "Computing value..." 42
    console.log(getValue()); // 42
    

缺点

  1. 内存泄漏:闭包会导致被其引用的变量无法被垃圾回收,此时这些内存无法被其他程序所利用,从而易造成内存泄漏。解决方式-1 为:在不需要使用闭包时,手动清理闭包引用(即将指向闭包的变量赋值为 null)。解决方式-2 为使用闭包而不创建闭包

    function createClosure() {
        var largeArray = new Array(1000000).fill('data');
        return function() {
            console.log(largeArray[0]);
        };
    }
    
    var closure = createClosure(); // 由于 largeArray 被闭包引用,所以无法被垃圾回收
    closure = null; // 解除对闭包的引用,允许垃圾回收器回收 largeArray
    
    createClosure(); // 使用闭包,而不创建闭包
    
  2. 性能问题:因为闭包会持有其词法作用域中的变量,从而会导致这些变量的生命周期变长,从时间的角度来说占用了更多内存。此外,闭包的原理是基于作用域链查找,使用闭包时,JS 引擎需要在多层作用域链中查找变量,从而影响执行效率。每次创建闭包时,都会涉及到内存分配操作。频繁创建和销毁闭包会增加垃圾回收的频率和开销,影响程序整体性能。解决方式:尽量重用闭包,减少闭包的创建次数,减少不必要的作用域嵌套。

  3. 代码复杂性:闭包的使用会增加代码的复杂性,使得代码可读性下降,从而可维护性降低。

REFERENCES

https://www.runoob.com/w3cnote/closure-intro.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值