节流函数必须用闭包维持lasttime等状态变量,核心是通过闭包“记住”上次执行时间以限制高频调用;时间戳版立即执行但丢弃尾部,定时器版首执立即后续周期执行,增强版支持leading/trailing配置。

节流函数(throttle)的核心是控制函数执行频率,而闭包正是实现“记住上一次执行时间”的关键——它让内部函数能持续访问并更新外部作用域中定义的时间戳变量。
闭包变量保存 lastTime
在节流函数定义时,将 lastTime 声明在外部函数作用域中,返回的节流后函数通过闭包引用它。每次调用都不会重置该变量,而是复用并更新它:
function throttle(fn, delay) {
let lastTime = 0; // 闭包变量:只初始化一次,后续调用共享
return function(...args) {
const now = Date.now();
if (now - lastTime >= delay) {
fn.apply(this, args);
lastTime = now; // 更新时间戳
}
};
}
为什么必须用闭包而不是全局或参数传入
如果把 lastTime 放在全局,多个节流函数会互相干扰;如果每次调用都传参,就无法自动维护状态。闭包提供的是独立、私有、持久的状态容器:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 每个
throttle(fn, delay)调用生成一个新闭包,拥有自己的 lastTime - 不同节流实例之间完全隔离,互不影响
- 时间戳生命周期与返回函数绑定,不依赖外部管理
常见增强写法:支持 leading 和 trailing
实际项目中常需首次立即执行(leading)或结尾补发一次(trailing),这时仍靠闭包维持多个状态变量:
function throttle(fn, delay, options = {}) {
let lastTime = 0;
let timer = null;
const { leading = true, trailing = false } = options;
<p>return function(...args) {
const now = Date.now();
if (leading && now - lastTime >= delay) {
fn.apply(this, args);
lastTime = now;
} else if (trailing) {
clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(this, args);
lastTime = Date.now();
}, delay);
}
};
}</p>这里的 lastTime、timer、options 全部靠闭包保持,各自独立。
验证闭包是否生效的小技巧
可以打印闭包中变量的引用地址或使用调试器断点观察其值变化:
- 在返回函数内加
console.log(lastTime),多次调用会看到数值递增而非重置 - 用
console.dir(throttledFn)查看函数的[[Scopes]],能看到 Closure 下挂载的 lastTime - 把
let lastTime = 0改成var lastTime = 0不影响逻辑,但语义上 let 更准确体现块级私有状态
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










