顾名思义,所谓闭包就是**“封闭的包裹**”,意味着对外隐藏包裹内容。
为什么需要了解闭包?
对于任何一个JavaScript开发者来说,理解闭包可以看做是另一种意义上的重生。闭包是纯函数编程语言的一个特性,因为它大大简化复杂的操作,所以很容易在一些JavaScript库以及其他高级代码中找到闭包的使用。
并且这是个在JavaScript中经常谈论到的问题,被问及到什么是闭包,如果你无法回答,那么,你必定是一个初级的JavaScript开发者…
大家一定在各种论坛和博客等处查找过闭包的相关资料,但大多是描述的比较模糊,或者说即便你理解了,当天睡一觉,第二天还是会问自己什么是闭包?
那么在这里,我们将以简短易懂的方式带领大家理解闭包的概念
网上对闭包的概念主要分以下两个观点:
但这两个观点都不足以说服什么是闭包
你说函数套函数就是闭包?
const fun = ()=>{
let num = 0;
(function (){
num += 1;
})();
return num;
};
const data = fun();
console.log(data); //1
const data2 = fun();
console.log(data2); //1
const data3 = fun();
console.log(data3); //1
const data4 = fun();
console.log(data4); //1
函数套函数就是用来解释闭包太不严谨,上面的实例代码,每次得到的data都是重新初始化的fun函数,且内部的num每次也都会重新初始化
你说在函数外获取函数内部变量就算是闭包?
function fun() {
var innerVal = '内部变量';
return innerVal;
}
var getInnerVal = fun ();
console.log(getInnerVal);
但是这和闭包没有丝毫关系…
闭包产生的时机
根据《你不知道的JavaScript》中的定义**“当函数作用域可以记住并访问所爱的词法作用域时,就产生了闭包,不论函数是在当前词法作用域还是内执行”**来查看这段代码:
const fun = ()=>{
let num = 0;
(function (){
num += 1;
})();
return num;
};
fun();
虽然从概念上算是闭包,但似乎没什么作用,因为外部fun函数的执行,也立即执行了内部的匿名函数,则内部匿名函数可以记录num的状态,但由于我们每次都重新初始化fun函数内部的num变量,所以num每次的结果就是1;
所以在这里我们得出,闭包产生的时机是外部函数执行,内部函数存在的时候就形成了闭包
简单来说就是:
技术上的闭包:
如何将上面那个没用的闭包变得有用呢?看下面的例子
const fun = ()=>{
let num = 0;
return (v)=>{
return num += v;
};
}
const data5 = fun(); //初始化函数fun并得到函数的匿名函数返回值(这里只初始化了一次)
console.log(data5(1)); //1 给匿名函数传参并得到累加的结果
console.log(data5(1)); //2 由于fun函数未重新初始化,且此时num的值为1,所以累加得2
console.log(data5(1)); //3 与上面雷同
由于主函数的返回值是一个匿名函数,所以我们通过return的方式每次操作那个匿名函数,而这个匿名函数则记录了num的状态,所以就形成了闭包
是不是只有这种return的方式才能形成闭包?
这是一个误解,我们使用其他例子来实现闭包
const obj = new Object();
const fun = ()=>{
let num = 0;
obj.method = (v)=>{
return num += v;
};
};
fun();
console.log(obj.method(1)); //1
console.log(obj.method(1)); //2
console.log(obj.method(1)); //3
console.log(obj.method(1)); //4
由外部Object对象中的方法来记录函数内部的状态变化
let objFun;
const fun = ()=>{
let num = 0;
objFun = (v)=>{
return num += v;
};
};
fun();
console.log(objFun(1)); //1
console.log(objFun(1)); //2
console.log(objFun(1)); //3
console.log(objFun(1)); //4
由函数外部的objFun转换为函数记录函数内部变化状态
const arr = [];
const fun = ()=>{
let num = 0;
arr.push((v)=>{
return num += v;
});
};
fun();
const data = arr[0](1);
console.log(data);
const data2 = arr[0](1);
console.log(data2);
由外部数组元素中的函数来保存函数内部的状态变化
所以由此证明了return和闭包没什么关系,只要将内部函数视为可观察可操作的核心,就能够形成闭包。
什么时候需要闭包?
参考文章:
https://juejin.im/post/5d61182c51882543e84f41e7
https://juejin.im/post/5b081f8d6fb9a07a9b3664b6
https://juejin.im/post/5d3e55aff265da1bc552ac5d#comment