闭包它在百度百科中的解释原话是这样的:闭包就是可以读取其余函数内部变量的函数。例如在javascript
中,只有函数内部的子函数才能读取局部变量,因此闭包能够理解成定义在一个函数内部的函数。在本质上,闭包是将函数内部和函数外部链接起来的桥梁。javascript
下面来一一解读这段话。java
首先来直接回答这个问题:闭包是什么?闭包
答案:闭包是一个函数,什么函数呢?一个定义在函数内部的函数。例如:异步
var add = (function () {
var counter = 0;
return function () {
return counter += 1;
}
})();
复制代码
在上面的例子中,函数内部return
的这个函数function () {return counter += 1;}
,它就是一个闭包。咱们直接把add
在控制台打印出来: 函数
add
,它其实是一个函数,可是这个函数倒是在另外一个函数内部建立的,这个就是
定义在函数内部的函数。
即咱们要解读这句话:可以读取其余函数内部变量的函数。性能
咱们知道,在JavaScript
中,有全局变量和局部变量。顾名思义,全局变量它是公有的、共享的,程序内的全部函数均可以直接调用这个全局变量,即它的做用域是全局性的;而局部变量,在函数内部声明的变量,它是私有的,只在函数内部起做用,在该函数以外的地方是没法被调用的,它的做用域是局部性的。ui
function add() {
var counter = 0;
return counter += 1;
}
console.log(add()); // 1
console.log(add()); // 1
console.log(add()); // 1
// 本意是想输出 3, 但事与愿违,输出的都是 1
复制代码
以上代码将没法正确输出,每次调用add()
函数,计数器都会设置为1
。能够将它写成闭包的形式,使counter = 0
只执行一次,并返回函数表达式,而后获得咱们想要输出的结果。spa
function add() {
var counter = 0;
return function () {
return counter += 1;
}
}
var closure = add();
console.log(closure()); // 1
console.log(closure()); // 2
console.log(closure()); // 3
复制代码
闭包它能够访问函数上一层做用域的局部变量,它使得函数拥有私有变量变成可能。3d
百度百科里面还有这么一段话:“闭包”一词来源于如下二者的结合:要执行的代码块(因为自由变量被包含在代码块中,这些自由变量以及它们引用的对象没有被释放)和为自由变量提供绑定的计算环境(做用域)。code
这句话含有一个意思,就是在闭包内部的变量它是不会被销毁的,会一直存在内存中,而且不会受到外界的干扰。在上面的例子中counter
的值就是这样受到闭包的保护,只能经过closure
方法去修改。
闭包有两个做用,一个是能够访问到局部变量,另外一个就是让这些变量的值始终保持在内存中。咱们能够用闭包来解决一个经典的问题:
for (var i = 1; i <= 5; i++) {
setTimeout(function() {
console.log(i);
}, 10)
}
复制代码
由于setTimeout
是个异步函数,因此会先把循环所有执行完毕,这时候i
就是6
了,因此会输出一堆6
。这个时候咱们就能够用闭包去解决这个问题啦:
for (var i = 1; i <= 5; i++) {
(function(j) {
setTimeout(function timer() {
console.log(j);
}, 10)
})(i)
}
复制代码
在上面的代码中,咱们首先使用了当即执行函数将i
传入函数内部,这个时候值就被固定在了参数j
上面不会改变,当下次执行timer
这个闭包的时候,就可使用外部函数的变量j
,从而达到目的。
固然,解决这个问题还能够用let
和传入setTimeout
的第三个参数,在这里就不一一展开描述了。
闭包由于会把变量保存在内存中,能够用来生成一个计时器,也就是文章开始的这个例子。
var add = (function () {
var counter = 0;
return function () {
return counter += 1;
}
})();
复制代码
一、闭包会使得函数中的变量都被保存在内存中,会增大内存的使用量,而且使用不当会容易形成内存泄漏。
由于,在JavaScript
的垃圾自动回收机制中有这么一句话:从逻辑上讲,永远不能释放进入环境的变量所占用的内存,由于只要执行流进入相应的环境,就可能会用到它们。由于进入闭包的变量是有可能继续使用的,即它们不会被自动回收,这个时候须要咱们手动回收清除。
二、若是不是由于某些特殊任务而须要闭包,在没有必要的状况下,在其它函数中建立函数是不明智的,由于闭包对脚本性能具备负面影响,包括处理速度和内存消耗。
最后,推荐观看下面关于闭包的这篇文章: