实现 before 方法

基础知识

  1. 什么是 before 函数? before 是一个高阶函数,它接收一个数字 n 和一个函数 func 作为参数,然后返回一个新函数。这个新函数的功能是:确保原始函数 func 在其被调用n 次之前可以正常执行。从第 n 次调用开始,新函数将不再执行 func,而是返回最后一次成功执行 func 时的结果。

    简单来说,before(n, func) 创建了一个最多只能成功调用 n - 1 次的函数。

  2. once 的关系 once 函数是 before 函数的一个特例。一个只允许执行一次的函数 once(func),其行为等价于 before(2, func)。因为 before(2, func) 允许在第 2 次调用 之前 执行,即只允许成功调用第 1 次。

  3. 应用场景 before 函数非常适用于那些需要限制执行次数的场景,特别是对于一些一次性或有限次数的初始化、设置或事件绑定。

    • 一次性初始化: 确保一个复杂的初始化逻辑只执行一次。const init = before(2, setupApp);
    • 有限的免费试用: 比如一个功能只允许用户免费试用 3 次。
    • 防止重复绑定: 确保某个事件监听器只被绑定有限的次数。

核心思路

before 函数的实现核心,与 debouncethrottle 类似,都依赖于闭包来维护一个持久化的状态。

  1. 高阶函数与闭包: before(n, func) 作为高阶函数,会返回一个新的函数。这个新函数通过闭包,可以持续访问并修改定义在 before 函数作用域内的变量。

  2. 计数器状态: 我们需要一个计数器(就是参数 n 本身)来追踪剩余的可执行次数。每当返回的新函数被调用时,这个计数器就减一。

  3. 条件执行: 在新函数内部,通过一个 if 语句来检查计数器的值。只有当计数器的值仍然大于 0 时,才执行原始函数 func

  4. 结果缓存: 为了实现“第 n 次调用及之后,返回最后一次成功执行的结果”,我们需要另一个闭包变量(例如 result)来存储 func 最后一次成功执行时的返回值。当执行次数耗尽后,后续的调用将直接返回这个缓存的 result

代码实现

下面是一个 before 函数的清晰实现。

/**
 * 创建一个函数,这个函数在被调用 n 次之前,会一直调用 func;
 * 第 n 次及之后,将返回最后一次调用 func 的结果。
 * @param {number} n - 函数可被调用的次数上限(不包括第 n 次)
 * @param {Function} func - 需要限制执行次数的函数
 * @returns {Function} - 返回一个新的函数
 */
function before(n, func) {
  let result; // 1. 用于缓存最后一次成功执行的结果

  // 参数校验
  if (typeof func !== 'function') {
    throw new TypeError('Expected a function');
  }

  // 2. 返回一个新的包装函数
  return function (...args) {
    // 3. 每次调用时,先将 n 减 1,然后判断是否大于 0
    if (--n > 0) {
      // 4. 如果次数未耗尽,则执行 func,并缓存结果
      result = func.apply(this, args);
    }

    // 5. 如果次数已耗尽(n <= 0),则 func 将不再执行
    // 无论是耗尽还是未耗尽,都返回 result
    // 对于耗尽后的调用,将一直返回上一次缓存的结果
    return result;
  };
}

代码解析

  1. 闭包变量初始化

    • let result 作为闭包变量,存储 func 最后一次有效调用的返回值,初始化为 undefined
    • 该变量通过闭包被 before 函数返回的包装函数持久化共享,实现结果缓存。
  2. 包装函数结构

    • before 核心是返回新函数,捕获 nresult 变量,形成持久化状态空间。
    • 包装函数接收参数并处理调用逻辑,控制原始函数 func 的执行次数。
  3. 执行次数控制逻辑

    • 核心条件if (--n > 0),利用前置递减运算符 --n 先减 1 再判断。
    • 示例说明before(3, myFunc) 调用过程:
      • 第 1 次:n=3→22>0 成立,执行 myFunc
      • 第 2 次:n=2→11>0 成立,执行 myFunc
      • 第 3 次:n=1→00>0 不成立,不执行。
      • 第 4 次及以后:n≤0,均不执行。
    • 实现“在第 n 次调用前执行”的逻辑,即总共执行 n-1 次。
  4. 函数执行与结果缓存

    • --n > 0 成立时,通过 result = func.apply(this, args) 执行 func
    • apply 确保 func 执行时 this 上下文正确,参数传递无误。
    • 每次执行结果存入闭包变量 result,实现结果缓存。
  5. 结果返回机制

    • 执行次数未耗尽时,返回当前 func 调用结果 result
    • 执行次数耗尽后,直接返回最后一次成功调用的 result(缓存值),后续调用均返回该值,保证结果一致性。
Copyright © Jun 2025 all right reserved,powered by Gitbook该文件修订时间: 2025-07-03 17:35:08

results matching ""

    No results matching ""

    results matching ""

      No results matching ""