【js】闭包及其内存保存简单易懂的介绍

闭包

闭包(closure)是指:形成了闭包的函数+及其周围被引用的存在 打包在一起
闭包 = 形成闭包的函数 + 被引用的(裁剪过的)作用域

其中,函数形成闭包的条件是:它引用了更大的作用域中的变量
(比如嵌套函数:子函数引用了亲函数中的变量)

也就是说:

//这里形成的闭包包括:
function outerFunction() {
    // 包括outerFunction的(被裁剪的)作用域
    let outerVariable: number = 10; // 包括我,因为我被引用了
    let outerVarAnother: number = 20; // 不包括我,因为我没被引用,被裁剪掉了

    function innerFunction(): void {// 包括我,我就是那个形成闭包的函数
        // 内部函数引用外部函数的变量,形成闭包
        console.log("外部变量的值 = " + outerVariable);
    }
    
    return innerFunction; // 返回内部函数
}

闭包通常是在嵌套函数中实现的(但并不是只有返回一个小函数的大函数能造成闭包!)

闭包的意义

好处:

闭包允许通过内部函数访问外部函数的作用域
这种特性让异步回调成为可能的

坏处:

闭包内的变量不会自动销毁,会被“一直”保存在内存中

闭包的内存保存机制

js的内存管理是基于作用域链的。垃圾回收器定期遍历作用域链,不在链中的变量被视为垃圾,进行删除。

在普通(无闭包)的情况下,在函数执行完毕后:
局部活动对象(包含所有挂在这个活动对象下的变量,也就是函数内的变量)被销毁
内存中只剩下全局作用域(包含所有挂在变量对象下的变量,也就是全局变量)

但在有闭包的情况下:

嵌套函数的情况:

以嵌套函数为例,代码见下:
如果没有手动 closureExample = null;,那么在closureExample还存在的时间内

  • innerFunc一直被引用
  • number一直被innerFunc引用
  • 因此,outerFunc(裁剪后的作用域)会一直占用内存。

在这种情况下,outerFunc占用内存的时间 = closureExample占用内存的时间,而不是在outerFunction();执行完毕后就可以被垃圾回收。

function outerFunction() {
    let outerVariable: number = 10; // 外部函数的变量


    function innerFunction(): void {
        console.log("外部变量的值 = " + outerVariable);
    }


    return innerFunction; // 返回内部函数
}

let closureExample: (() => void) | null = outerFunction(); // 调用外部函数,获取内部函数
closureExample(); // 调用内部函数
closureExample = null;//垃圾回收number
/*
假设上下文中只有let closureExample: (() => void) | null = outerFunction();这一个对innerFunc的引用,那么:
closureExample = null;
1 - 手动删除对innerFunc的引用
2 - innerFunc的变量对象(outerFunc.number的引用)被垃圾回收
3 - outerFunc的变量对象(包括outerFunc.number)引用清零,被垃圾回收
*/
异步回调的情况:

以异步回调为例,代码见下:

  • 在setTimeout执行之前,data会一直被保存在内存中
  • 在setTimeout执行callback(data)之后,(假设上下文中没有其他对这个闭包的引用),data才能被垃圾回收。

注意,这里不需要像嵌套函数一样手动删除引用,因为这里的闭包函数并没有(通过return)暴露给外界去引用。setTimeout执行完毕,它的变量对象直接挂掉,data也就能被自动删除了。

function fetchData(callback:(result: string)=>any) {
    let data = "这是外部函数的数据"; // 外部函数的变量

    setTimeout(function() {
        callback(data); // 在回调函数中访问外部函数的变量,形成闭包
    }, 1000);
}

fetchData(function(result) {
    console.log(`回调函数中获取到的数据为: ${result}`);
});
  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值