once
/**
* Ensure a function is called only once.
*/
export function once<T extends (...args: any[]) => any>(fn: T): T {
let called = false
return function () {
if (!called) {
called = true
fn.apply(this, arguments as any)
}
} as any
}
这段代码实现了一个 函数调用一次执行器(once decorator
),核心功能是确保被包装的函数仅执行一次,后续调用将被忽略。以下是逐层解析:
1. 核心逻辑
闭包状态管理:通过 let called = false 在闭包中保存调用状态,外部无法直接修改,保证状态隔离。
首次调用拦截:返回的函数内部通过 if (!called)
判断,首次调用时将 called
设为 true
并执行 fn(...args)
,后续调用直接跳过。
2. 类型设计(TypeScript)
泛型约束:T extends (...args: any[]) => any
确保 fn
必须是函数类型(接受任意参数,返回任意值),增强类型安全性。
类型断言:as T
强制将返回的函数类型匹配为输入函数类型,避免类型推导冲突(例如处理 this
和 arguments
的兼容性)。
3. 关键细节
this
绑定:使用 fn.apply(this, arguments)
确保被包装函数执行时 this
指向与原始调用上下文一致。
参数传递:arguments
是类数组对象,通过 apply
展开为正式参数,兼容任意数量和类型的参数。
惰性求值:fn
实际执行被延迟到第一次调用时,实现按需初始化。
4. 示例场景
const logOnce = once(() => console.log("Logged once!"));
logOnce(); // 输出 "Logged once!"
logOnce(); // 无输出(函数已锁定)
总结
该模式广泛应用于需要 资源初始化、事件触发限制、防重复提交 等场景(如单例模式、按钮防抖)。其精髓在于通过闭包封装状态,结合函数柯里化实现行为控制,是函数式编程中 高阶函数 的典型应用。
本文地址:https://www.tides.cn/p_vue-source-once