闭包是JavaScript中老生常态的话题,如何理解闭包,以及该怎样使用,下面就跟我一起来看看吧。
概念
- 红宝书:闭包是指有权访问另一个函数作用域中变量的函数
- MDN: 闭包是指那些能够访问自由变量的函数,这里的自由变量是指外部作用域中的变量
- 个人理解:闭包 = 内层函数 + 引用外层函数变量
先来看个例子:
function out() {
const a = 1;
function fn() {
console.log(a);
}
fn()
}
out()
从这个例子可以得出,闭包一定有return吗?闭包一定会内存泄漏吗?当然不是的,接着往下看。
闭包中什么时候用到return呢?
外部想要使用闭包的变量,则需要return
function out() {
const a = 1;
return function (){
console.log(a);
}
}
const fn = out();
fn()
return的目的是把内部的局部变量返回到外面来,让外面也可以使用这个值
闭包的好与坏
-
闭包的好处:
- 变量长期驻扎在内存中
- 避免污染全局变量
- 私有成员的存在
-
闭包的坏处:
- 增大内存的使用量
- 容易造成内存泄漏
实现数据私有
let i = 1;
function fn() {
i++;
console.log(`调用次数${i}`);
}
fn()
这里i是一个全局变量,很容易就被修改,如果对i进行修改,影响调用的次数,这个时候就可以使用闭包的形式“私有化”
function fn() {
let i = 1;
function count() {
i++;
console.log(`调用次数${i}`);
}
return count
}
const res = fn()
res()
这样就实现了“私有化” 不能直接修改i的值了
造成内存泄漏的操作
先来说说什么是内存泄漏和垃圾回收器
- 内存泄露:当已经不需要某块内存时这块内存还存在着,没有被释放,导致该内存无法被使用
- 垃圾回收器:执行环境负责管理代码执行过程中使用的内存。JS的垃圾回收机制是为了以防内存泄漏
造成泄漏的操作
- 意外的变量:变量引用、变量未申明。当变量使用不当,没有及时回收(手动赋值
null) - 计时器或回调函数
- 当不需要
Interval或者timeout时,最好调用clearInterval或者clearTimeout来清除
- 当不需要
function out () {
var name = 'Jack'
var age = 20
function bar () {
console.log(name)
console.log(age)
}
return bar
}
var fn = out()
fn()
fn = null // 阻止内存泄漏
fn函数调用完毕之后,out函数会自动销毁,但out函数中的变量name和age不会被销毁,因为在bar函数内部进行了访问,并且根据垃圾回收机制,被另一个作用域引用的变量不会被回收。除非bar函数解除调用才能销毁。 如果该函数使用的次数很少,不进行销毁的话就会变为闭包产生的内存泄漏。
window.onload = function(){
var el = document.getElementById("id");
var id = el.id; //解除循环引用
el.onclick = function(){
alert(id);
}
el = null; // 将闭包引用的外部函数中活动对象清除
}
退出函数之前,将不使用的局部变量全部删除,可以使变量赋值为null
function setCallback() {
let counter = 0;
return function cb() {
counter++; // 只有计数器是回调范围的一部分
console.log(counter);
}
}
const timer = setInterval(setCallback(), 1000);
clearInterval(timer); // 停止计时器,比如如果按下按钮
引用setInterval没有被清除,它自身不会被清除需要手动clearInterval