这是我参与8月更文挑战的第10天,活动详情查看:8月更文挑战
做前端的可太需要了解闭包了,几乎每个面试都会问到闭包,闭包的重要性不言而喻。什么是闭包:闭包一般是指那些引用了另一个函数作用域中变量的函数,通常是在嵌套函数中实现的。也就是说,闭包让你可以在一个内层函数中访问到其外层函数的作用域。
function f1() {
var a = 666;
function f2() {
console.log(a);
}
return f2; // f1返回了f2的引用
}
var jackson = f1(); // jackson就是f2函数了
jackson(); // 执行jackson,全局作用域下没有a的定义,
//但是函数闭包,能够把定义函数的时候的作用域一起记住,输出666
上面的例子,首先有执行上下文f1,在f1中定义了函数f2,而通过对外返回f2的方式让f2得以执行。当f2执行时,访问了f1内部的变量a。这个时候闭包就产生了。
闭包很有用,因为它允许将函数与其所操作的某些数据(环境)关联起来。这显然类似于面向对象编程。在面向对象编程中,对象允许我们将某些数据(对象的属性)与一个或者多个方法相关联。因此,通常你使用只有一个方法的对象的地方,都可以使用闭包。
闭包中使用this会让代码变得复杂,之前的文章说过this指向问题,每个函数在被调用的时候都会自动创建俩个特殊变量:this和arguments。内部函数不可以直接访问外部函数的这俩个变量,但是可以把this保存到闭包就可以行得通。我们先看一下直接访问。
window.identity = 'Jackson';
let obj = {
identity: 'bear',
getIdentityFunc() {
return function () {
return this.identity;
};
}
};
console.log(obj.getIdentityFunc()()); // 'Jackson'
看一下把this保存到变量that。
window.identity = 'Jackson';
let obj = {
identity: 'bear',
getIdentityFunc() {
let that = this;
return function () {
return that.identity;
};
}
};
console.log(obj.getIdentityFunc()()); // 'bear'
在定义匿名函数之前,先把this保存一下,在定义闭包时,可以让它访问that,这是因为包含函数中名称没有任何冲突的一个变量。即使在外部函数返回后,that仍然指向obj。
因为闭包会保留他们包含的函数作用域,所以它比其他函数更占用内存,过度使用闭包而不释放的话就会导致过度占用。解决方法是,在退出函数之前,将不使用的局部变量全部删除,我们在之前讲过垃圾回收,点击查看(JavaScript的垃圾回收 (juejin.cn))
在旧版本浏览器中,尤其是ie,如果把html元素保存在闭包的作用域中,就相当于该元素不能被销毁。
function clickaaa() {
let element = document.getElementById('aaa');
element.onclick = () => console.log(element.id);
}
这里写了一个点击aaa元素,让它输出aaa的id,只要这个函数存在,element的计数就至少等于1,也就是永远不会被回收。想让它回收的话我们在后面把它释放掉就可以了,大家一定要养成良好习惯。
function clickaaa() {
let element = document.getElementById('aaa');
element.onclick = () => console.log(element.id);
element = null;//释放
}