概述一下什么是 JS 中的闭包,以及它的优缺点的一个简单总结 :

JS 中,闭包 是一个神奇的存在,这篇文章概述一下 JS  中的闭包的 概念,以及它的 优缺点的一个简单总结 :


  • 闭包概念 :

闭包是 js 中的一大特色,也是一大难点。简单来说,所谓闭包就是说,能够读取其他函数内部变量的函数;或 简单理解为定义在一个函数内部的函数,内部函数持有外部函数内变量的引用

通常情况下,变量作用域两种:全局变量、局部变量。js 中函数内部可以读取全局变量,函数外部不能读取函数内部的局部变量。要想从外部读取函数内部的变量,就会用到闭包。

  • 闭包特性 :
  1. 函数嵌套函数;
  2. 函数内部可以引用函数外部的参数和变量;
  3. 参数和变量不会被垃圾回收机制回收;
  • 闭包的使用场景 :函数作为返回值
function print(){
    var name="dov"
    return function(){
        return name;
  }
}
var b = print();
console.log(b())//输出 dov

/*===============================
在这段代码中,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 循环,按顺序打印出当前的循环次数
for(var i=0; i< 5; i++){
    setTimeout(function(){
        console.log(i + '')
    },100);
}

/*==============================================
按照预期它应该依次输出1 2 3 4 5,而结果它输出了五次5,这是为什么呢?因为setTimeout()函
数要等执行完函数调用栈中的代码,然后立即调用定时器。这是因为,我们的定时器都被放在了一个
被称为队列的数据结构中,等待上下文的可执行代码运行完毕后,才开始运行定时器,也就是定时器
才刚开始同时计时。所以在定时器的方法执行的时候,变量i已经变成了5,所以输出的全部是5。
==============================================*/

解决上述问题的方法 1 :

ES6 中提出了一个新的关键字 let ,就可以声明一个仅对当前 “{}” 内部有作用的变量。把 for 循环里面的 var 变成 let, 实现预期结果;

解决上述问题的方法 2 :

引入闭包来保存变量 i,将 setTimeout 放入立即执行函数中,将 for 循环中的循环值 i 作为参数传递,100毫秒后同时打印出1 2 3 4 5, 如果我们想实现每隔 100毫秒 分别依次输出数字  i*100;

for(var i=1; 1<5; i++){
    (function(i){
        setTimeout(function(){
            console.log(i)
        },i*100)
    })(i)
}
  • 闭包的使用场景 :闭包作为参数传值 
var num =15;
var fn1=function(x){
    if(x>num){
        console.log(x)
    }
}
void function(fn2){
    var num = 100;
    fn2(30)
}(fn1)//输出 30

/*=======================================================
在这段代码中,函数fn1作为参数传入立即执行函数中,在执行到fn2(30)的时候,30作为参数传入
fn1中,这时候if(x>num)中的num取的并不是立即执行函数中的num,而是取创建函数的作用域中的
num这里函数创建的作用域是全局作用域下,所以num取的是全局作用域中的值15,即30>15,打印30
========================================================*/
  • 闭包优点 :
  1. 希望一个变量长期存储在内存中;
  2. 避免全局变量的污染;
  3. 私有成员的存在;
  • 闭包缺点 :
  1. 被引用的私有变量不能被销毁,增大了内存消耗,造成内存泄漏,解决方法是可以在使用完变量后手动为它赋值为null;(常驻内存,增加内存使用量,使用不当会很容易造成内存泄露。)
  2. 其次由于闭包涉及跨域访问,所以会导致性能损失,我们可以通过把跨作用域变量存储在局部变量中,然后直接访问局部变量,来减轻对执行速度的影响;

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值