闭包原理及使用场景

闭包

闭包指有权访问另一个函数作用域中变量函数

函数套函数,内部函数访问外部函数变量,必须return,从而避免了变量被销毁

    //这个例子中,闭包就是fn()函数
    function fn(){
      var num=1;
      function fun(){
        console.log(num);
      }
        return fun;
    }

有些人可能会问到,既然闭包这么麻烦,为什么不使用全局变量呢?是因为这种临时变量如果大量在全局中,会影响访问速度。如果有一个处理过程很耗时的函数,我们就要先将计算出的值存储起来,当调用这个函数时,会先在缓存中查找,找不到才会进行计算并更新缓存。闭包可以做到这一点,因为他不会释放外部的引用,从而函数内部的值得以保留。

闭包demo

点击小li输出索引

传统操作

    //1.利用动态添加属性的方式
    var lis =document.querySelector('.nav').querySelectorAll('li')
    for(var i=0;i<lis.length;i++){
      lis[i].index=i;
      lis[i].onclick = function(){
        // console.log(i);//不用自定义属性index,输出的都是4,因为内部访问不到for循环里的i,点击时,i已经变成了4
        console.log(this.index);
      }
    }

闭包操作

    //2.利用闭包的方式得到当前小li的索引号
    for(var i=0;i<lis.length;i++){
      //创建了4个立即执行函数
      (function(i){//接收参数
        lis[i].onclick=function(){
          console.log(i);
        }
        // console.log(i);
      })(i);//立即执行函数的参数,先把i读进去
    }

这样子闭包会产生内存泄漏,数据都无法销毁

定时输出小li内容

错误示范:

    var lis = document.querySelector('.nav').querySelectorAll('li')
    for(var i=0;i<lis.length;i++){
      setTimeout(function(){
          console.log(lis[i].innerHTML);
      },3000)
//计时器是异步的,在任务队列里,for是立即执行的,i早就被变成4了
    }

使用闭包:

    for(var i=0;i<lis.length;i++){
      (function(i){
        //使用闭包,i一直跟着变,最后在3s后输出所有
        setTimeout(function(){
          console.log(lis[i].innerHTML);
        },3000)
      })(i)
    }

思考题

思考题1

请添加图片描述

本案例没有使用闭包,函数内部就没有局部变量

执行object.getNamefunc()–>

返回的function(){ return this.name }–>

返回this.name–>

object.getNamefunc()()相当于function()()即为立即执行函数–>

立即执行函数this指向的是window–>

this.name即为window.name=The Window

结果为The Window

思考题2

请添加图片描述

本案例使用了闭包,that使用了上一个函数的属性

中间将this指向的object存了起来

结果为My Object

闭包的常见使用场景

原生的setTimeout
// 使用setTimeout传递的第一个函数不能带参数
setTimeout(function(params) {
	console.log(params)
}, 1000)
// undefined

函数的参数无法为将要执行的函数提供参数,此时就需要闭包

function log(num) {
    return function() {
        console.log(`${num}秒后打印`)
    }
}
setTimeout(log(2), 2000)

// 第2秒后打印
用闭包模拟私有方法

编程语言中JAVA是支持将方法声明为私有的,而JavaScript没有这种原生支持,但可以使用闭包来模拟私有方法。私有方法不仅仅有利于限制对代码的访问:还提供了管理全局命名空间的强大能力,避免了非核心的代码弄乱了代码的公共接口。

var Counter = (function() {
    var privateCounter = 0   // 私有变量
    function changBy(val) {
        privateCounter += val
    }
    return {
        intcrement: function() {  // 三个闭包共用一个词法语境
            changBy(1)
        },
        delcrement: function() {
            changBy(-1)
        },
        value: function() {
            return privateCounter
        }
    }
})()

console.log(Counter.value()) // 0
Counter.intcrement()
Counter.intcrement()
console.log(Counter.value()) // 2
Counter.delcrement()
console.log(Counter.value()) // 1

var Counter1 = Counter()
var Counter2 = Counter()  // 每个闭包都是引用自己词法作用域内的变量privateCounter

console.log(Counter1.value(), Counter2.value()) // 0 0
Counter1.intcrement()
console.log(Counter1.value(), Counter2.value()) // 1 0

一个闭包内对变量的修改,不会影响另一个闭包的变量

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

会飞的战斗鸡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值