JS基础:闭包产生的条件和优缺点

问题:闭包产生的三个条件

  1. 必须是嵌套关系
    function A() {
    	function B() {
        }
    }
    
    
  2. 内部函数引用了外部函数中的数据(属性、函数)
    例如:
    function A() {
      var a = "a";
      function B() {
        console.log(a);
      }
    }
    
    
  3. 执行外部函数(也可理解为定义内部函数)
    function A() {
      var a = "a";
      function B() {
        console.log(a);
      }
    }
    A();
    
    

 再放一段经典的产生闭包的代码:

function foo() {
    var a = 2;

    function bar() {
        console.log(a);
    }

    return bar;
}

var baz = foo();

baz(); //2 

一个产生闭包的关键角色:垃圾回收器
正常情况下foo()函数在执行结束以后,foo()整个的作用域都会被垃圾回收器销毁。但是var baz = foo()这里变量baz是foo()函数返回的bar()函数的引用,且bar()中还使用了foo()的变量,因此foo()函数的作用域会一直存在,且可以在foo()函数作用域之外还可以访问foo()的作用域。这样就产生了一个闭包。


闭包的最大用处有两个:一个是前面提到的可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。

→ 优点:   
 1.保护函数内的变量安全    
 2.在内存中维持一个变量(用的太多就变成了缺点,占内存) ;    
 3. 逻辑连续,当闭包作为另一个函数调用的参数时,避免你脱离当前逻辑而单独编写额外逻辑。    
 4. 方便调用上下文的局部变量。    
 5. 加强封装性,可以达到对变量的保护作用。  
 → 缺点:   
  1.常驻内存,会增大内存使用量,使用不当很容易造成内存泄露。   
   2.还有有一个非常严重的问题,那就是内存浪费问题,这个内存浪费不仅仅因为它常驻内存,更重要的是,对闭包的使用不当会造成无效内存的产生。 
  → 特性:  
   1. 函数嵌套函数   
   2. 内部函数可以访问外部函数的变量    
   3. 参数和变量不会被回收。

用闭包实现防抖和节流:

防抖简单来讲就是 当一个持续事件( 如:onscroll )一直执行时,若我们有一个事件触发函数( 如:console.log(1)),我们不想让这个函数一直触发,而是当事件停止后再触发,这就叫防抖

function debounce(fn,delay){
    let timer = null //借助闭包
    return function() {
        if(timer){
            clearTimeout(timer) 
        }
        timer = setTimeout(fn,delay) 
    }
}

function showTop  () {
    var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
  console.log('滚动条位置:' + scrollTop);
}
window.onscroll = debounce(showTop,1000)

如上,我们不会在滚动条滚动时一直打印,而是在停止后打印一次高度。

节流

类似节流,如果我们想在事件一直发生时间接性的 、有规律的触发一个函数,而不是只在结束时触发一次,这就叫节流

function throttle(fn,delay){
    let valid = true
    return function() {
       if(!valid){
           //休息时间 暂不接客
           return false 
       }
       // 工作时间,执行函数并且在间隔期内把状态位设为无效
        valid = false
        setTimeout(() => {
            fn()
            valid = true;
        }, delay)
    }
}
/* 请注意,节流函数并不止上面这种实现方案,
   例如可以完全不借助setTimeout,可以把状态位换成时间戳,然后利用时间戳差值是否大于指定间隔时间来做判定。
   也可以直接将setTimeout的返回的标记当做判断条件-判断当前定时器是否存在,如果存在表示还在冷却,并且在执行fn之后消除定时器表示激活,原理都一样
    */

// 以下照旧
function showTop  () {
    var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
  console.log('滚动条位置:' + scrollTop);
}
window.onscroll = throttle(showTop,1000) 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值