js 闭包
# js 闭包
闭包是指有权访问另一个函数作用域中的变量的函数
闭包是函数式编程
闭包的三个特性:
函数嵌套函数
函数内部可以引用函数外部的参数和变量
参数和变量不会被垃圾回收机制回收
# 闭包关联知识点
自由变量是指在函数中使用的,但既不是函数参数也不是函数的局部变量的变量,其实就是另外一个函数作用域中的变量。
闭包中的变量并不保存中栈内存中,而是保存在堆内存中
# 创建闭包函数的两种情况
函数作为返回值
函数作为参数传递
# 闭包优点
避免全局变量的污染
模块化代码:使用自执行的匿名函数来模拟块级作用域
es6 没出来之前,用 var 定义变量存在变量提升问题
for (var i = 0; i < 10; i++) {
console.info(i);
}
alert(i)(
// 变量提升,弹出10
//为了避免i的提升可以这样做
function() {
for (var i = 0; i < 10; i++) {
console.info(i);
}
}
)();
alert(i); // underfined 因为i随着闭包函数的退出,执行环境销毁,变量回收
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
- 在内存中维持一个变量,可以做缓存(但使用多了同时也是一项缺点,消耗内存)
# 闭包缺点
参数和变量常驻内存,增加内存使用量。
使用不当会很容易造成内存泄露
# 使用闭包注意点
- 由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在 IE 中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。
function showId() {
var el = document.getElementById("app");
el.onclick = function() {
aler(el.id); // 这样会导致闭包引用外层的el,当执行完showId后,el无法释放
};
}
// 改成下面
function showId() {
var el = document.getElementById("app");
var id = el.id;
el.onclick = function() {
aler(id); // 这样会导致闭包引用外层的el,当执行完showId后,el无法释放
};
el = null; // 主动释放el
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。
this 指向问题
var object = {
name: ''object",
getName: function() {
return function() {
console.info(this.name)
}
}
}
object.getName()() // underfined
// 因为里面的闭包函数是在window作用域下执行的,也就是说,this指向windows
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# 闭包一定会造成内存泄漏吗
准确的说是在 IE9 之前才会有闭包变量内存泄漏的问题。
因为 IE9 之前采用的垃圾回收算法不是现在使用的清除标记算法,而是引用计数算法。
引用计数算法在处理 COM 对象(组件对象模型)会有循环引用的问题,而循环引用才是导致内存泄漏的元凶。
在早期的 V8 中,由于闭包引用的变量被挂载了全局的大对象 windows 中,所以这一变量由老生代区采用标记清除算法进行回收。频繁的垃圾回收会生成大量的内存碎片,所以也会导致内存泄漏问题。
为了解决这一问题,以及频繁的垃圾回收导致的全停顿问题(垃圾回收在主线程执行),后来 v8 又采用了标记清除整理算法,以及增量回收、并行回收、并发回收等垃圾回收技术,所以在新一代浏览器中,使用闭包几乎不会出现内存泄漏问题。
# 什么时候闭包会清除?
将闭包的函数置为 null
更新时间: 2/10/2022, 7:21:32 PM