877 字
4 分钟
Js中的闭包
2022-08-05

什么是闭包#

闭包的概念

函数和对其词法环境lexical environment的引用捆绑在一起构成闭包

​ 也就是说,闭包可以让内部函数访问外部函数的作用域。在本质上,闭包是将函数内部和函数外部连接起来的桥梁。

最简单的例子#

function compare(propertyName) {
function(obj1,obj2){
let value1 = obj1[propertyName]
let value2 = obj2[propertyName]
return (value1 - value2 < 0)
}
}
NOTE

​ 在这个例子中,内部的匿名函数中的变量value1和value2,引用了外部函数的propertyName变量

闭包的特点#

特点
  • 函数嵌套函数
  • 函数内部可以引用函数外部的参数和变量
  • 参数和变量不会被垃圾回收机制回收

闭包的一些应用#

1. 使用闭包模拟私有方法#

NOTE

​ 使用闭包来定义公共函数,并令其可以访问私有函数和变量,这种方式也叫模块方式

​ 两个计数器counter1和counter2是相互独立的

​ 其它例如计数器、延迟调用、回调等闭包的应用,其核心思想还是创建私有变量和延长变量的生命周期

const Counter = function () {
let privateCounter = 0
function changeBy(val) {
privateCounter += val
}
return {
increment: function () {
changeBy(1)
},
decrement: function () {
changeBy(-1)
},
value: function () {
return privateCounter
}
}
}
const counter1 = new Counter()
const counter2 = new Counter()
counter1.increment()
counter1.increment()
console.log(counter1.value()); // 2
console.log(counter2.value()); // 0
// ...

2. 函数柯里化#

NOTE

​ 柯里化的目的在于避免频繁调用具有相同参数函数的同时,又能够轻松的重用

function getArea(width, height) {
return width * height
}
const area1 = getArea(10, 20)
const area2 = getArea(10, 30)
const area3 = getArea(10, 40)
// 如果我们碰到的长方形的宽老是10,我们可以使用闭包柯里化这个函数
function getArea(width) {
return (height) => {
return width * height
}
}
const getTenWidthArea = getArea(10)
// 之后碰到宽度为10的长方形就可以这样计算面积
const area = getTenWidthArea(20)
// 而且如果遇到宽度偶尔变化也可以轻松复用
const getTwentyWidthArea = getArea(20)

3. 定时器和闭包#

for(var i = 0;i<5;i++){
setTimeout(()=> {
console.log(i)
},100)
}
// 结果是输出 5 次 5
WARNING

​ 先来看一个例子,这个例子大家应该都知道为什么

var只有函数作用域,而{}相当于形成了一个块作用域,所以5次循环用的是同一个i,再加上for循环内部的seTimeout还是一个异步任务,所以在执行seTimeout的回调之前,i就先自增到了5

解决:

  • 最简单的解决办法可以将var改为ES6中的let
  • 引入闭包来保存变量(立即执行函数)
for(var i = 0;i<5;i++){
(function(i) {
setTimeout(() => {
console.log(i)
},100)
})(i)
}
// 0 1 2 3 4

如果想每隔100毫秒依次输出,而不是同时:

for (var k = 0; k < 5; k++) {
(function(k) {
setTimeout(() => {
console.log(k)
}, 100 * k)
})(k)
}

闭包的使用场景#

NOTE
  • 创建私有变量
  • 延长变量的生命周期

闭包的总结#

优点
  1. 可以访问到函数内部的局部变量
  2. 可以避免全局变量的污染
  3. 这些变量的值始终保持在内存中,不会在外层函数调用后被自动清除。
缺点

会增大内存使用量,滥用闭包会影响性能,导致内存泄漏等问题。

在退出函数之前,将不使用的局部变量全部删除,可以使变量赋值为null,这样就会被回收.#
Js中的闭包
https://blog.oceanh.top/posts/frontend/闭包/
作者
Ocean Han
发布于
2022-08-05
许可协议
CC BY-NC-SA 4.0
最后修改时间
2026-03-19 13:03:26