携手创作,共同成长!这是我参与「掘金日新计划 · 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,达到记忆返回结果只执行一次的效果