前言
在编程、面试中我们经常会遇到闭包,那么闭包是什么?它能给我们带来什么不一样的地方?它的使用场景在哪里?
介绍闭包
- 定义:能够读取其他函数内部变量的函数
- 作用:
- 通过函数中暴露出的方法读取函数中的私有变量
- 使得函数中的私有变量一直保存在内存中
- 通过闭包可以保存函数的私有变量
- 特性:
- 一般我们是在函数中嵌套另一个函数,并且将函数内部的函数进行返回
- 内部函数有权访问函数外的参数和变量
- 函数中的参数和变量不会被 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(this, arguments);
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(this, arguments);
timer = null;
}, delay);
}
}
div1.addEventListener('drag', throttle(function(e) {
console.log(e.offsetX, e.offsetY);
}), 200)
总结
平时我们开发时经常会使用闭包,但是不要忘释放内存哦!