2020-04-20|2020-04-20 JS闭包
闭包是指有权访问另一个函数作用域中的变量的函数。
闭包的作用:
- 可以在函数的外部访问到函数内部的局部变量。
- 让这些变量始终保存在内存中,不会随着函数的结束而自动销毁。
我们首先知道闭包有3个特性:
①函数嵌套函数
②函数内部可以引用函数外部的参数和变量
③参数和变量不会被垃圾回收机制回收
本文我们以闭包两种的主要形式来学习
一个闭包简单的例子
function a(){
var name = 'sll';
return function(){
return name;
}
}
var b = a();
console.log(b())
a()中的返回值是一个匿名函数,这个函数在a()作用域内部,所以它可以获取a()作用域下变量name的值,将这个值作为返回值赋给全局作用域下的变量b,实现了在全局变量下获取到局部变量中的变量的值
一个经典的闭包例子
function fn(){
var num = 3
return function(){
var n = 0
console.log(++n)
console.log(++num)
}
}
var fn1 = fn()
fn1() //(1,4)
fn1() //(1,5)
一般情况下,在函数fn执行完后,就应该连同它里面的变量一同被销毁,但是在这个例子中,匿名函数作为fn的返回值被赋值给了fn1,这时候相当于fn1=function(){var n = 0 … },并且匿名函数内部引用着fn里的变量num,所以变量num无法被销毁,而变量n是每次被调用时新创建的,所以每次fn1执行完后它就把属于自己的变量连同自己一起销毁,于是乎最后就剩下孤零零的num,于是这里就产生了内存消耗的问题
再来看一个经典例子-定时器与闭包
for (var i = 0;
i < 5;
i++) {
setTimeout( ()=>{
console.log(i)
},100)
}
按照预期它应该依次输出1 2 3 4 5,而结果它输出了五次5,这是为什么呢?原来由于js是单线程的,所以在执行for循环的时候定时器setTimeout被安排到任务队列中排队等待执行,而在等待过程中for循环就已经在执行,等到setTimeout可以执行的时候,for循环已经结束,i的值也已经变成5,所以打印出来五个5,那么我们为了实现预期结果应该怎么改这段代码呢?(ps:如果把for循环里面的var变成let,也能实现预期结果)
for (var i = 0;
i < 5;
i++) {(function(i){
setTimeout( ()=>{
console.log(i)
},100)
})(i)
}
最后总结一下闭包的好处与坏处 好处
①保护函数内的变量安全 ,实现封装,防止变量流入其他环境发生命名冲突
②在内存中维持一个变量,可以做缓存(但使用多了同时也是一项缺点,消耗内存)
③匿名自执行函数可以减少内存消耗
【2020-04-20|2020-04-20 JS闭包】坏处
①被引用的私有变量不能被销毁,增大了内存消耗,造成内存泄漏,解决方法是可以在使用完变量后手动为它赋值为null;
②其次由于闭包涉及跨域访问,所以会导致性能损失,我们可以通过把跨作用域变量存储在局部变量中,然后直接访问局部变量,来减轻对执行速度的影响
推荐阅读
- 2018-05-30闭包和函数
- 闭包-定时器-BOM
- 【转自CSDN】《史上最全前端开发面试问题及答案整理》
- 2020-04-20怎么做才能把乳胶漆的质感完美表现出来呢()
- 掌握Javascript面试(什么是闭包())
- 深入学习作用域和闭包—全面(JS系列之二)
- 每日精进111/200|每日精进111/200 2020-04-20
- 从【预编译】到【声明提升】到【作用域链】再到【闭包】
- POJ|POJ - 3660 Cow Contest 传递闭包floyed算法
- 原型,原型链和闭包以及this指向问题