有权访问另一个函数作用域中的变量的函数。通俗地讲,一个函数有权去访问另一个函数作用域中的变量,这个函数就称为闭包。闭包函数在执行完以后,这个函数中还存在一部分在内存当中,没有被垃圾回收机制回收。
来个例子:
var test = function father() { var data = 'from father'; return function son() { return data; } }(); console.log(test()); //输出 'from father'解析一下这段代码: 首先这里定义了一个 test 变量,这里 father 后面加了个(),说明他自执行了,return 了一个函数 son 赋值给到 test,那么现在 test 被赋的值是 son 这个函数,接下来执行 test 函数,也就是执行 son 函数,son 函数又将外层的在 father 函数内部的 data return 了出去,于是输出了 form father。也就是说,son 函数访问到了 father 函数内部的变量 data,形成了闭包。
因为js的函数作用域的关系,一般情况下外部是访问不了函数内部的变量的,设计闭包结构就可以访问到函数内部的变量,还有就是闭包可以让变量长期保存在内存里,生命周期较长
for循环异步问题,函数防抖及函数节流问题,封装私有变量等等。
for循环异步问题:
先看一个例子(来自牛客网):
<ul> <li>click me</li> <li>click me</li> <li>click me</li> <li>click me</li> </ul> var elements = document.getElementsByTagName('li'); var length = elements.length; for (var i = 0; i < length; i++) { elements[i].onclick = function () { alert(i); } }点击之后,输出是 4,为什么不是分别的0,1,2,3 呢? 解析一下这段代码: 首先 for 循环是同步机制,onclick 是异步机制,这里 for 循环执行的时候,遇到了 onclick 事件,因为 onclick 是异步,于是把它放在异步队列中,继续执行 for 循环,直到 i = 4 了,开始依次执行异步队列的 onclick 函数,onclick 函数中 alert 了 i 这个变量,这个 i 变量呢,就是来自 for (var i = 0; i < length; i++) 中的 i,注意看,这个 i 是 全局变量,也就是说,onclick 函数 alert 的 i 是来自全局的变量 i,前面说到 i 已经是 4 了,所以实际上 alert 的 i 就是全局变量的 i 也就是 4 了。
使用闭包解决:
var elements = document.getElementsByTagName('li'); var length = elements.length; for (var i = 0; i < length; i++) { elements[i].onclick = function father (num) { return function son () { alert (num) } }(i) }输出是 0,1,2,3,这次达到目的了。 解析一下这段代码: 修改过后,按照之前的逻辑,for 循环先执行完,开始依次执行异步队列中的 onclick 函数,这里可以开始看 onclick 被赋值了什么,先看 father 函数,看到它后面有个 (i),说明这里它自执行了并且将那一次循环中的 i 作为参数传进了 father 函数中,father 函数执行后,return 了一个 son 函数,最终这个 son 函数赋值到 onclick,现在开始点击页面中的 li 标签,就会执行刚才赋值的 son 函数,son 函数会 alert num 这个变量,再看看 num 这个变量从哪儿来,num 这个变量来自于 函数 father 从外界接收的参数,也就是在 for 循环时传给 father 函数的参数 i,而这个 i 参数从哪来,是分别从 i = 0、1、2、3 的时候传进去的,最后输出也就是 0,1,2,3。
缺点:如果闭包滥用会造成内存泄露,影响页面性能,每次用完之后要立刻释放资源,把引用指针指向null