个人闭包理解(结合代码)
使用debounce函数做了一个闭包的个人理解<!DOCTYPE html>
<html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>function debounce</title> </head> <body> <button class="btn">点击按钮</button> <div> <p>测试防抖效果:</p> <p class="text"></p> </div> <script> function debounce(fn, delay) { let timeId; return function() { if (timeId) clearTimeout(timeId); timeId = setTimeout(fn, delay); } } /* 包含上下文:又称 包含作用域: 当前函数所在的上下文(作用域)为其包含上下文(包含作用域) */ /* 包含上下文变量对象 又称 包含作用域变量对象: 函数执行时会先创建其包含(上下文/作用域)变量对象:其初始属性和值为arguments,其他变量或者函数在预编译阶段添加,var会将变量直接初始化,let和const则只对变量进行声明,在代码执行过程中调用只声明未初始化的变量名称会报错 */ /* 利用闭包实现;闭包思路理解: 当debounce函数调用时,返回了一个函数,即clickFun,后debounce上下文(作用域)在执行栈中销毁,clickFun保留了其包含上下文变量对象(可自己理解名称为debounce的一个对象)。其timeId的值为undefined(可理解为debounce.timeId = undefined);当执行clickFun函数时,会给timeId赋值setTimeout(fn, delay),(理解为debounce.timeId = setTimeout(fn, delay)),即再次调用函数clickFun会有一个timeId = setTimeout(fn, delay)的timeId初始值,而因为debounce函数没有调用,所以debounce中的timeId值不会重新初始化为undefined */
const clickFun = debounce(() => { text.innerHTML='点击按钮之后1秒内不点击按钮则触发防抖事件'; }, 1000); console.log(clickFun); /* 打印值为 ƒ () { if (timeId) clearTimeout(timeId); timeId = setTimeout(fn, delay); } */ const btn = document.querySelector('.btn'); const text = document.querySelector('.text'); btn.addEventListener('click', clickFun); </script> </body> </html>
// 闭包存在的作用:timeId定义为了debounce局部变量中,没有定义到全局中,防止了变量名称污染全局作用域。同时,使用闭包函数延伸了timeId的作用范围,使外部作用域可以在不重复调用debounce函数的情况下对timeId进行使用。
// 使用闭包的话会在内存中保存其相关的包含作用域变量对象,大量使用闭包会造成内存泄漏。
// 可优化点:在确定不再使用闭包函数的情况下可以将保存闭包函数的变量值赋值为null
// 代码中clickFun变量仅为理解闭包运行定义,可以不定义此变量,直接在addEventListener中调用debounce(()=>{}, 1000)的方式调用闭包函数