前言
很多小伙伴在面试的时候都会被问到,闭包是什么?举例说明下闭包的运用场景?
八股文谁不会背呀,上网一搜,临时抱下佛脚便是。嘿嘿,我当时就是这么干的。
但是想要在面试中脱颖而出,死记硬背理论是远远不够的,面试官如果问的再深入一些,就要凉凉。
关于闭包的讨论和文章有很多,但我个人认为,许多都没有讲到核心点上。所以自己总结一番,加深自己理解的同时,也希望能帮助到各位看官。
闭包,究竟是什么
闭包就是能够读取其它函数内部变量的函数。
但凡背过面试题的朋友,对这句话就一定不会陌生。网上对于闭包的解释,十之八九离不开这句话,大差不差。
以这句话来解释闭包,没错,但没有灵魂,像一个复读机。
我们首先要知道,闭包存在的意义是什么?可以简单概括为,实现从外部读取函数内部的局部变量。
我们有时候需要获取到函数内部的局部变量,正常情况下,这是办不到的。只有通过变通的方式才能实现,比如在函数内部,再定义一个函数。举个栗子:
function f1() {
var a = 1;
function f2() {
alert(a);
}
f2();
}
f1(); // 可以获取到局部变量 a
请回答我,上栗是不是闭包?
是不是在 f1 函数内部定义了一个 f2 函数?
是不是 f2 函数读取到了 f1 函数内部的局部变量?
那么,这到底是不是闭包呢?
如果你迟疑了,我们再看个栗子。获取函数内部的局部变量,其实并不需要那么费劲,还有一种更简单的方法:
function f() {
var a = 1;
return a;
}
f();
这是闭包吗?大家都知道,很显然,它不是。第一个栗子也不是。
那么,到底怎样才算是闭包呢?我们来看一下真正的闭包:
function f1() {
// 定义一个局部变量
var a = 1;
// 定义一个函数,引用了局部变量 a
function f2() {
a++;
console.log(a);
}
// 将内部函数 f2,return 出去
return f2;
}
// 调用 f1,返回的是 f2 函数,赋值给 f
var f = f1();
// 调用 f,打印 a 的值为 2
f();
同样是访问函数内部的局部变量,为什么需要写的这么麻烦呢?为什么之前那样变通的写法就不算是闭包呢?继续看栗子:
// 闭包
function f1() {
var a = 1;
function f2() {
a++;
console.log(a);
}
return f2;
}
var f = f1();
f(); // 2
f(); // 3
f(); // 4
不断调用 f,变量 a 的值会一直累加。由于函数 f 引用着变量 a 的值,导致变量 a 不会被垃圾回收机制自动回收,所以它的值会一直保存在内存中。
// 非闭包
function f1() {
var a = 1;
function f2() {
a++;
console.log(a);
}
f2();
}
f1(); // 2
f1(); // 2
f1(); // 2
每次调用,变量 a 的值都是 2。每次调用,函数以及内部变量都会重新创建,执行完毕之后就会销毁。
有的朋友可能会想到,把变量 a 定义到全局不也能实现长久保存吗:
var a = 1;
function f() {
a++;
console.log(a);
}
f(); // 2
f(); // 3
f(); // 4
是的,可以实现。但是全局变量很容易造成污染,在实际项目开发中,我们不可能定义那么多的全局变量。
总结一波:
闭包的作用:闭包最大的用处有两个,一个是前面提到的可以读取函数内部的局部变量,另一个就是让这些变量的值始终保存在内存中。
什么时候使用闭包:局部变量无法共享和长久保存,而全局变量可能造成污染,当我们希望有一种机制既可以共享、长久保存变量,还不会造成污染时,就需要运用闭包。
闭包的定义:闭包是一种现象,当一个函数返回的是一个函数,并且被返回的这个函数对于局部变量存在引用,就形成闭包。
闭包的弊端:由于闭包会导致变量长驻在内存中,过度使用闭包可能会造成内存泄漏。
闭包具体的使用场景
比较经典的有:
- 模块化
- 函数节流
- 函数防抖
- 函数柯里化 关于闭包的具体使用场景有很多,以上仅供参考,想再深入的朋友可以看看其它文章,我就不一一展开讲了~
最后
如果文中有错误或者不足之处,欢迎大家在评论区指正。
你的点赞是对我莫大的鼓励!感谢阅读~