闭包是什么
学习闭包前可以先看看作用域,只要懂了js作用域,自然而然你就懂了闭包
在mdn中是这么描述闭包的:
闭包(closure)是一个函数以及其捆绑的周边环境状态(lexical environment,词法环境)的引用的组合。换而言之,闭包让开发者可以从内部函数访问外部函数的作用域。在 JavaScript 中,闭包会随着函数的创建而被同时创建。
当内部函数使用了外层函数的变量就会产生闭包,不用等内部函数执行,定义时就已经形成闭包。
如果你认为闭包要有return,那么理解就已经错了
闭包的产生
function demo() {
let n = 1;
function aaa() {
console.log(n);
}
aaa()
}
demo();
上面这个例子中,有一个变量n,一个函数demo,demo可以访问到n变量,那么这就是一个闭包

还有一个情况,使用return将内部函数保存到外部
function demo() {
let n = 1;
function aaa() {
console.log(n);
}
return aaa;
}
const test = demo();
test();

为什么要嵌套函数
嵌套函数是为了让变量变成局部变量,所以才把n放在一个函数中,如果不把n放在一个函数中,那么n就会是一个全局变量,从而达不到闭包私有化变量的目的。
一定要使用return吗
如果不用return将内部函数保存到外部,你就无法使用这个闭包,也可以将函数设置为window的属性,或者使用表达式赋值到外部
例如:作为对象的属性值,赋值给另一个变量(变量名 = 函数)
所以使用return只是为了能让内部函数被使用。
闭包的作用
闭包经常用于私有化一个变量,让其他函数无法修改这个变量
假设我现在有一个按钮,点击一次就显示我点了多少次,如果不用闭包,那可以直接设置为一个全局变量
但是设置一个全局变量非常不安全,别人可以随意更改这个值,此时就可以使用闭包私有化这个变量
function a() {
let num = 0;
function b() {
num++;
return `你已经点击了${num}次了`;
}
return b;
}
let demo = a();

注意
如果此时再创建一个demo1,demo和demo1这两个闭包的作用域是不同的

闭包例子图解1
function a() {
function b() {
let bbb = 234;
console.log(aaa);
}
let aaa = 123;
return b;
}
let glob = 100;
let demo = a();
demo();
a函数执行前
在执行a函数前,声明的全局变量都保存在全局对象中,全局对象里面保存的属性目前是这样

此处省略了全局对象的其他属性
a函数定义时将全局对象的作用域放在自己作用域的最顶端

a函数执行
a函数执行时,产生自己的作用域并将自己的作用域放在作用域链的最顶端,他的作用域里有aaa变量和b函数

a函数执行期间,b函数被定义,b函数定义的时候是站在a函数的肩膀上看世界的,也就是b函数出生时拿着父亲a的作用域在看世界

b被保存到外部
a函数将b函数return到外部之后,a函数就运行完了,a函数运行完之后,a函数会销毁他的作用域(其实是断开指向,只是叫销毁),但是,b函数被保存出去了,b函数还拿着a函数的作用域,所以即使a执行完后断开了指向,但是b函数的作用域链中还有指向a函数的作用域,所以a函数的作用域不会被释放,所以b函数还是能使用a函数的作用域

所以运行demo,会打印123

闭包例子图解2
function demo() {
let food = "";
let obj = {
eat: () => {
if (food === "") {
console.error("没有食物");
} else {
console.log(`I'm eating ${food}`);
food = "";
}
},
add: newFood => {
food = newFood;
},
};
return obj;
}
let test = demo();
这个例子是另一种产生闭包的情况,函数作为一个对象的属性被保存到了外部,但是,闭包的形成条件就是,只要内部函数使用了外层函数的变量,那么就会形成闭包
demo函数执行
demo函数执行,将自己的作用域放在了作用域链的最顶端,里面有food变量和obj对象

demo函数执行时,obj对象里的eat和add两个函数被定义,两个函数都用着demo的作用域

obj被保存到外部
obj被return到外部之后,demo销毁作用域,两个函数还是指向着demo的作用域,所以不会被释放

由于闭包后都是使用同一个变量,所以就会产生下面的结果。

优点和缺点
优点
1.能够读取函数内部的变量
2.可以让变量一直存在内存中,使用后不会被垃圾回收机制回收
3.可以实现变量私有化,加强了封装性,不会产生变量污染
缺点
正所谓物极必反,由于闭包不会释放变量,变量会一直存在于内存中,对内存的消耗很大,如果滥用闭包,会影响页面的性能
在IE中可能会导致内存泄漏
解决办法:在退出函数时,将不用闭包置空,赋值为null
总结
闭包其实就是内部函数引用外层函数的变量,我们使用时经常会将函数保存到外部,所以内部函数保存到外部后还用着外层函数的变量,导致外层函数执行完后作用域无法释放,从而形成闭包
以上都是我个人理解,如果问题请多指教

本站资源多数存于云盘,如有失效请邮件联系我们,我们将迅速处理。
本网站的文章部分内容可能来源于网络,如有侵权,请联系service#asuu.cn进行删除处理。
暂无评论内容