JS中的闭包
要想了解闭包,我们就必须首先了解JS中的函数
因为在JS中函数是一等公民
一等公民的意思就是函数的使用是十分灵活的
函数可以作为另外一个函数的参数,也可以作为另外一个函数的返回值来使用。
JS中的闭包的定义:
JS中的一个函数,如果访问了外层作用域的变量,那么他就是一个闭包
闭包产生的三个必要条件
- 函数的嵌套
- 内部函数体内存在访问外部函数体定义的局部变量
- 外部函数被调用
例如
function outer() {
//外部函数定义的局部变量
let foo = 10;
let bar = 100;
function inner1() {
console.log('Hello World');//内部函数没有访问外部函数定义的任何变量,不形成闭包
}
function inner2() {
foo ++; //使用了外部函数定义的变量,形成闭包
console.log(foo);
}
function inner3(bar) {
bar --; //内部函数参数表中存在和外部函数定义变量的同名参数,参数表优先级高,不形成闭包
console.log(bar);
}
}
outer();
闭包的作用及生命周期
// 借助闭包
function outer() {
let foo = 10;
function inner() {
foo ++;
console.log(foo);
}
return inner; //将闭包return到全局
}
let fn = outer();
//不借助闭包
function outer() {
let foo = 10;
foo++;
return foo;
}
console.log(outer()); 11
console.log(outer()); 11
//原本代码运行到这一行时,局部变量foo内存已经被回收,但因为形成了闭包,局部变量foo将继续存在
fn(); //foo => 11
fn(); //foo => 12
局部变量的生命周期由跟随外部函数结束改为跟随闭包结束,换言之,局部变量的生命周期被延长了
允许在函数的外部借助闭包访问函数内的局部变量,但全局环境依然无法直接操作局部变量
闭包在外部函数调用完毕后,栈内存中的闭包名称立即释放
如果闭包没有被return到全局,则栈内存中的函数对象也被立即释放
如果闭包被return到全局,则闭包堆内存中的函数对象会保留至整个javascript程序结束
//程序运行至此行内部函数inner由于被return到全局,所以会一直存在
// 所以我们如果我们要防止内存泄漏,需要手动结束闭包的生命周期
fn = null;
内存泄漏的案例
function createFnArray() {
// 一个整数在内存中占据4个字节,1024字节等于1kb,1024kb等于1mb
// 所在该数组占据的空间是4M
var arr = new Array(1024 * 1024).fill(1);
return function () {
console.log(arr.length);
};
}
var arrayFn = createFnArray();
// arrayFn = null
在此处 如果我们不将arrayFn设为空,也不使用arrayFn,那么就会白白浪费掉4MB的内存空间,造成内存泄漏
应用实例:
//利用函数定义一个模块
function Foo() {
//定义不希望模块外部直接访问的变量
let name = 'tom';
let age = 10;
let alive = true;
function grow() {
age ++; //长大一岁
}
function kill() {
alive = false; //去世
}
return {
grow: grow,
kill: kill,
}
}
//利用闭包
let foo = Foo();
foo.grow(); //age 自增
foo.kill(); //弄死Foo,但遗体尚在
foo = null; //灰飞烟灭,尸骨无存
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了