一文走近JavaScript中的闭包
在讲述闭包之前, 让我们先来看看MDN中是怎么解释闭包的
闭包(closure)是一个函数以及其捆绑的周边环境状态(lexical environment, 词法环境)的引用的组合. 换而言, 闭包让开发者可以从内部函数访问外部函数的作用域. 在 JavaScript 中, 闭包会随着函数的创建而被同时创建.
听起来略微有些抽象
让我们来书写一个较为经典闭包, 逐渐地理解它的含义
Example---认识闭包
// 代码一
function a(){
var i = 0;
function b(){
i++
}
b();
}
a() // i == 1
a() // i == 1
a() // i == 1
// 代码二
function a(){
var i = 0;
function b(){
i++; // 此时函数a里面的函数b调用了外层函数
} // 中声明的变量i, 这个时候我们就说
return b; // 函数b和变量i形成了一个闭包
}
var c = a();
c() // i == 1
c() // i == 2
c() // i == 3
其中代码一的逻辑是比较好理解的, 结果也在情理之中
而代码二为什么可以做到i始终在增加呢
让我们来梳理一下其中的逻辑
初始化函数a, 在a中声明了一个变量i
随后初始化函数b, 其作用是i自增
最后返回函数b
此刻再创建一个变量c, 来接受函数a的返回值(即函数b)
当我们调用c时, 我们实现i的自增
当我们再次调用时, i继续自增
其中与代码一不同的就是, 在函数c被调用后, i并没有被js的垃圾回收机制回收
而是继续保留了下来, 在后续继续完成了自增的工作
闭包的特征和为什么选择使用闭包
根据上面的案例我们可以发现
闭包有以下三个特征
- 满足函数嵌套函数
- 内部的函数使用了外部函数的参数和变量
- 函数中的参数和变量不会被js的垃圾回收机制所回收
可能在这里就会产生疑惑了
闭包到底有什么用嘞, 这里直接使用全局变量不就好了吗
选择闭包的原因可以归纳为两点
- 全局变量容易造成重名, 进而发生变量污染
- 闭包在开发者能力范围内延长了变量的生命周期
看到这里, 相信现在你已经对闭包有了自己的一个认识
接下来让我们来闭包是如何贯彻我们学习js的道路
闭包的经典案例
// 返回值
function fn(){
var name="hello";
return function(){
return name;
}
}
var fnc = fn();
console.log(fnc()) // hello
// IIFE(自执行函数)
// 使用自执行函数构造一个私有的作用域, 从而弥补了js中没有私有变量的问题
var private = (()=>{
name = 'private'
sex = 'walmartBag'
return {
getName(){
return name
},
getSex(){
return sex
}
}
})()
console.log(private.getName())
console.log(private.getSex())
经典的案例还有很多, 我们就只说到这里, 如果还想了解更多的话可以来google
从闭包二字深入认识闭包
这是我在某个网站上看到某位佬写的, 分享给大家
闭包可分为"闭", "包"二字
"闭"即通过函数将其中的参数和变量封闭在一个作用域内, 外面无法直接访问
而"包"就是将它给打包, 分发给需要使用它的对象, 从而实现了生命周期的延长
闭包的缺点
虽然我们在上文用十分多的笔墨来写怎样实现闭包, 闭包有哪些好处
但是我们在使用闭包的时候要慎重
因为
变量并没有被回收, 会长时间的占据内存, 进而影响网页的性能(内存泄漏)
总结
万事万物皆有利有弊
代码世界也同样, 并不是非黑即白的
闭包在帮助我们延长变量生命周期的同时
也造成了内存泄漏
所以我们在使用它的时候需要好好地权衡权衡
ᕙ(`▿´)ᕗ
2023/5/19