once

栏目: source 发布时间:2025-10-15
/**
 * 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 强制将返回的函数类型匹配为输入函数类型,避免类型推导冲突(例如处理 thisarguments 的兼容性)。

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