闭包
网上讲闭包的文章一搜一大把。而且面试时,比较传统的问题都有很大几率提到闭包的问题。的确,闭包是js中一个很重要的部分。因为现在的前端开发,处处都是闭包,根本离不开闭包。无论是为了方便以后的开发能读懂代码,还是为了自己造轮子给全世界的人用,都得掌握闭包。
什么是闭包
引用《你不知道的JavaScript》中的定义:
当函数可以记住并访问所在的词法作用域时,就产生了闭包,即使函数是在当前词法作用域之外执行的。
如果用代码来说的话,就是这样
function outer () {
var a = 1;
return function inner () {
console.log(a);
}
}
var inner = outer();
inner() // 1
按道理,outer被执行完后,会被回收掉,它的作用域应该不可能再被访问到。但是由于它返回的内部函数,是嵌套在它作用域中的,内部函数对它的作用域还是保留访问权,因此它的作用域并没有被回收,被留在了内存中。这个时候,就大概懂得了闭包是个什么东西。简单点说,闭包就是一个定义在某个函数内部并且被当成返回值返回的函数,它可以让外部的环境访问到这个函数的内部作用域。那么闭包一般用来干什么?
闭包的用途
- 我开始学js时,有个很经典的讲解闭包的作用的例子,相信大家也看过:
let arr = [];
for (var i = 0; i <= 5; i++) {
arr[i] = function () {
console.log(i);
}
}
arr[2](); // 6
初学者咋一看,觉得应该输出2,但结果是6。但是如果你前面的作用域掌握了的话,其实很容易就明白发生了什么。首先这段代码是在同一个作用域内,不存在for的块级作用域,当循环一遍,arr这个数组里面也的的确确有6个项,每项都是个function, 但是调用它们中的任何一个时,按照作用域的寻值,其实是输出了用来循环的i,这个i在这个作用域是只有1个的, 此时这个i的的确确是6。所以并不是js错了,是我们自己错了。
那么如果想要达到一开始的需求,就可以用闭包,用闭包来创建一个作用域,来保存对那个时候的i值。(当然也可以用es6的let来达到块级作用域的效果)
代码如下:
for (var i = 0; i <= 5; i++) {
arr[i] = (function (i) {
return function() { console.log(i); }
})(i)
}
arr[2](); // 2
那么这个问题就可以用闭包来解决咯
- 自从逐渐开始接触更多的web开发后,就会接触很多轮子,或者和别人合作,自己得写一个模块,比如 微信sdk的模块。一般构建一个模块时,把私有的变量和私有的函数隐蔽在内部函数作用域中,然后只暴露需要给别人调用的接口。一方面可以保护代码不被别的代码污染变量或者函数,一方面方便别人调用,别人不需要知道你怎么实现,只要明白如何调用你的接口就好了。比如,下面的一个用户登录注册登出的模块(额,没有测试过,有问题轻喷):
let user = (function () {
async function login(form) {
try {
const { data } = await fetch('/session', { method: 'post', data: JSON.stringify(form) });
// success handle
} catch (err) {
// error handle
}
}
async function regist(form) {
try {
const { data } = await fetch('/user', { method: 'post', data: JSON.stringify(form) });
// success handle
} catch (err) {
// error handle
}
}
async function logout() {
try {
const { data } = await fetch('/session', { method: 'delete' });
// success handle
} catch (err) {
// error handle
}
}
return {
logout,
login,
regist
}
})();
以上就是js的闭包了,其实闭包,我个人感觉觉得理解后并不是很难,然后它也其实并不是有很多话可以说,因为它在js中太常见了。真的是处处都会是闭包。(然而那次面试某个团队时,却没有很好答出来,所以还是得好好掌握基础)