闭包防抖节流

150 阅读2分钟

作用域

作用域:运行代码时,变量/函数/对象的可访问性

好处:有独立的空间,变量不会暴露,即允许不同作用域下同名变量

全局作用域:任何地方都能访问到(容易命名冲突)

局部作用域:在固定代码段可访问(引发变量提升、预解析)

es6块级作用域:使用let/const关键字定义在代码块中(不会变量提升)

变量提升:先声明再调用,同名变量函数优先

作用域链

在函数内部调用某个变量,若当前作用域没有,则会一层层往上找,这就形成了作用域链。若最外层也没有,则会显示xx is not defined

undefined:定义了,但未赋值 
is not defined:没有定义,报错
null:空对象

闭包——函数内外部的桥梁

函数嵌套函数,内部函数(调用了外部函数的变量)就叫闭包

使用场景:防抖节流、设计单例模式

正常情况下,函数执行完后,需要释放内存空间,那么内部变量会被销毁

存在意义:1、能读取外函数的内部变量 2、缓存变量,不会被销毁(内外函数变量,相互依赖)
注意事项:1、不随意改变父函数中变量 2、不滥用闭包,变量保存在内存中,内存消耗大,容易造成内存泄漏

内存泄漏

不再使用的变量,由于某些原因,没有被释放 => 内存消耗大

结果:造成内存泄漏,浪费系统内存,程序运行速度减慢,甚至崩溃

解决措施:少用闭包、少用全局变量、定时器写完要释放、少用事件监听器

故许多语言(c#/js/java)都自带内存管理机制,也就是俗话说的垃圾回收机制
回收对象:不再使用的变量,释放他们占用的内存,且会按固定时间回收

防抖

用户触发事件过于频繁,只让最后一次输入生效

使用场景:搜索框输入时、窗口大小resize、手机号/邮箱验证输入检测

    //获取一次完整的输入值
    function debounce(fn,delay){
        let timer=null
        return function(){
            if(timer!==null){
                clearTimeout(timer)
            }
            timer=setTimeout(()=>{
                // console.log(this)
                // call:1、改变this指向 2、调用函数
                fn.call(this)
            },delay)
        }
    }
    let v=document.querySelector('input')
        v.oninput=debounce(function(){
        console.log(this.value)
    },500)

节流

控制高频事件执行的次数

使用场景:滚动加载、搜索框搜索功能

    //一定时间内执行一次(懒加载)
    function throttle(fn,delay){
        let flag=true
        return function(){
            if(flag){
                setTimeout(()=>{
                    fn()
                    flag=true
                },delay)
            }
            flag=false
        }
    }
    window.onscroll=throttle(()=>{
        console.log('我在滚动')
    },500)