JavaScript基础篇-闭包

220 阅读2分钟

前言

在编程、面试中我们经常会遇到闭包,那么闭包是什么?它能给我们带来什么不一样的地方?它的使用场景在哪里?

介绍闭包

  • 定义:能够读取其他函数内部变量的函数
  • 作用:
    • 通过函数中暴露出的方法读取函数中的私有变量
    • 使得函数中的私有变量一直保存在内存中
    • 通过闭包可以保存函数的私有变量
  • 特性:
    • 一般我们是在函数中嵌套另一个函数,并且将函数内部的函数进行返回
    • 内部函数有权访问函数外的参数和变量
    • 函数中的参数和变量不会被 JavaScript 的垃圾回收机制回收
  • 对闭包的理解:
    • 首先我们得先理解作用域,作用域是你有权访问的变量集合
    • 通过作用域我们就可以知道私有变量是什么了,私有变量是某个作用域下的变量,在这个作用域内才能访问这个私有变量
    • 闭包的主要作用是为了封装一些私有变量,并且不想让用户随意的修改这些变量,只能通过暴露函数中的方法去修改私有变量,而且这些变量会长久的保存在内存中,不会被 JavaScript 回收
  • 好处:
    • 能够实现变量的保存,并且不会造成全局污染
    • 使得变量长期保留在内存中
    • 私有化变量,外部不能直接访问
  • 注意点:
    • 因为闭包中的变量可以长期保留在内存中,所以我们使用时得谨慎使用,否则会造成内存泄露,影响全局性能
    • 在退出闭包函数(结束闭包函数)的时候需要删除闭包中的变量,释放内存
  • 使用场景:
    • 缓存变量,例如计时器、登陆框等
    • 利用闭包设计单例模式
    • JavaScript 中的防抖节流

场景代码

常见的闭包封装

function Closure() {
  let name = "oyzx";
  return function() {
    console.log(name);
  };
}
let fn = Closure();
fn()   // oyzx

利用闭包设置单例模式

class SingleMode {
    login() {
        console.log('login...')
    }
}
SingleMode.getVariable = (function() {
    let instance
    return function() {
        if(!instance) {
            instance = new SingleMode()
        }
        return instance 
    }
})()
let obj1 = SingleMode.getVariable()
obj1.login()
let obj2 = SingleMode.getVariable()
obj2.login()
console.log('obj1 === obj2', obj1 === obj2)

防抖节流

防抖

// 手写简单的防抖,以input输入(一般在搜索框体现)为例
const input1 = document.getElementById('input');
// 只执行最后一个函数
function debounce(fn, delay = 500) {
    let timer = null;
    return function() {
        if(timer) {
            clearTimeout(timer);
        }
        timer = setTimeout(() => {
            fn.apply(thisarguments);
            timer = null;
        }, delay);
    }
}
input1.addEventListener('keyup'debounce(function() {
    console.log(input1.value);
}), 600)

节流

// 手写简单的节流,以拖拽div为例
const div1 = document.getElementById('div');
function throttle(fn, delay = 100) {
    let timer = null;
    return function() {
        if(timer) {
           return
        }
        timer = setTimeout(() => {
            fn.apply(thisarguments);
            timer = null;
        }, delay);
    }
}
div1.addEventListener('drag'throttle(function(e) {
    console.log(e.offsetX, e.offsetY);
}), 200)

总结

平时我们开发时经常会使用闭包,但是不要忘释放内存哦!