lodash/once.js 实现一个 once 函数

943 阅读2分钟

image.png

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第8天,点击查看活动详情


实现一个 once 函数

最近看到一道手写题,题目是这样的: 实现一个 once 函数,记忆返回结果只执行一次

实现函数只执行一次的核心思想非常的简单:「通过记录是否被执行的状态,来决定函数是否需要被调用」

让我们看看lodash的源码,找到once.js

// once.js

import before from './before.js'

/**
 * Creates a function that is restricted to invoking `func` once. Repeat calls
 * to the function return the value of the first invocation. The `func` is
 * invoked with the `this` binding and arguments of the created function.
 *
 * @since 0.1.0
 * @category Function
 * @param {Function} func The function to restrict.
 * @returns {Function} Returns the new restricted function.
 * @example
 *
 * const initialize = once(createApplication)
 * initialize()
 * initialize()
 * // => `createApplication` is invoked once
 */
function once(func) {
  return before(2, func)
}

export default once

噢,核心在before.js,我们去before.js看看

// before.js

/**
 * Creates a function that invokes `func`, with the `this` binding and arguments
 * of the created function, while it's called less than `n` times. Subsequent
 * calls to the created function return the result of the last `func` invocation.
 *
 * @since 3.0.0
 * @category Function
 * @param {number} n The number of calls at which `func` is no longer invoked.
 * @param {Function} func The function to restrict.
 * @returns {Function} Returns the new restricted function.
 * @example
 *
 * jQuery(element).on('click', before(5, addContactToList))
 * // => Allows adding up to 4 contacts to the list.
 */
function before(n, func) {
  let result
  if (typeof func !== 'function') {
    throw new TypeError('Expected a function')
  }
  return function(...args) {
    if (--n > 0) {
      result = func.apply(this, args)
    }
    if (n <= 1) {
      func = undefined
    }
    return result
  }
}

export default before

可以看到,once.js调用before的时候,传了两个参数,第一个参数是数字2,第二个是一个函数。

function once(func) {
    return before(2, func);
}

然后就到before.js,看看做了什么处理。

先是用typeof判断func是否是函数,如果不是就抛出异常。

接着返回一个函数

return function(...args) {
    if (--n > 0) {
      result = func.apply(this, args)
    }
    if (n <= 1) {
      func = undefined
    }
    return result
}

函数主要就是判断--n大于0,如果大于0,就执行func,并用apply把this传过去,并把值赋值给result

result = func.apply(this, args)

这时候--n =》 --2 变成了1,进入下面判断,把func从内存中去掉

if (n <= 1) {
    func = undefined;
}

然后下次再进来before的时候,就会直接拿result返回,并不会再执行func,达到记忆返回结果只执行一次的效果