一、概念
闭包就是能够读取其他函数内部变量的函数。例如在javascript中,只有函数内部的子函数才能读取局部变量,所以闭包可以理解成“定义在一个函数内部的函数”。在本质上,闭包是将函数内部和函数外部连接起来的桥梁。
二、特性
-
函数嵌套函数
-
函数内部可以引用函数外部的参数和变量
-
参数和变量不会被垃圾回收机制回收
三、用法
1. 函数作为返回值
function closure(num) {
var count = num
// t()使用
// return function getCount() {
// return count++
// }
return {
plus: function() {
return count++
},
minus: function() {
return count--
},
getCount: function() {
return count
}
}
}
var t = closure(0)
console.log('初始值:' + t.getCount())
t.plus()
console.log('plus后:' + t.getCount())
t.minus()
console.log('minus后:' + t.getCount())
(1)经典例子-定时器与闭包
1.1 实现依次输入0 1 2 3 4
for (var i = 0; i < 5; i++) {
// var则输出5个5,改成let按顺序输出0-4
setTimeout(() => {
console.log(Date.now() + ' ' + i)
}, 100)
}
1.2 引入闭包来保存变量j,将setTimeout放入立即执行函数中,将for循环中的循环值j作为参数传递,100毫秒后同时打印出0 1 2 3 4
for (var j = 0; j < 5; j++) {
(function(j) {
setTimeout(() => {
console.log(Date.now() + ' ' + j)
}, 100)
})(j)
}
1.3 那如果我们想实现每隔100毫秒分别依次输出数字,又该怎么改呢?
for (var k = 0; k < 5; k++) {
(function(k) {
setTimeout(function() {
console.log(Date.now() + ' ' + k)
}, 100 * k)
})(k)
}
k*100是为4个定时器分别设置了不同的时间,同时启动,但是执行时间不同,每个定时器间隔都是100毫秒,实现了每隔100毫秒就执行一次打印的效果。
2. 闭包作为参数传递
// 第一种写法
function fun2() {
var num = 24
console.log(++num)
}
function fun1(fun) {
fun()
}
fun1(fun2)
// 输出结果
// 25
// 第二种写法(匿名函数回调)
void (function(fun) {
fun()
})(fun2)
// 输出结果
// 25
总结:
优点:
- 可以访问到函数内部的局部变量
- 可以避免全局变量的污染
- 这些变量的值始终保持在内存中,不会在外层函数调用后被自动清除。
缺点:
- 会增大内存使用量,滥用闭包会影响性能,导致内存泄漏等问题。