memoize.js

import eq from './eq';
import { mathCeil } from './internals/native';
function argsEqual(newArgs, lastArgs) {
    if (newArgs.length !== lastArgs.length) {
        return false;
    }
    for (let i = 0, len = newArgs.length; i < len; i++) {
        if (!eq(newArgs[i], lastArgs[i])) {
            return false;
        }
    }
    return true;
}
/**
 * 创建一个缓存 `func` 结果的函数。
 *
 * 如果上下文和参数一致,直接返回缓存结果,否则执行函数并缓存。
 *
 * 返回的函数含有一个 `clear` 方法,用于清除缓存。
 *
 * @alias module:Function.memoize
 * @since 1.17.0
 * @param {Function} func 要缓存结果的函数。
 * @param {Object} [options] 配置项。
 * @param {Function} [options.isEqual] 自定义比较参数方法。默认函数遍历参数并使用 `===` 进行比较。
 * @param {number} [options.max] 最大缓存数量,`0`表示不限制。默认`0`。
 * @returns 缓存 `func` 结果的函数。
 * @example
 * const memoizedValues = memoize(Object.values);
 * const object = { a: 1, b: 2 };
 * const other = { a: 3, b: 4 };
 *
 * memoizedValues(object); // [1, 2]
 * memoizedValues(other); // [3, 4]
 *
 * object.a = 2;
 * memoizedValues(object); // [1, 2]
 *
 * // 清空缓存
 * memoizedValues.clear();
 *
 * memoizedValues(object); // [2, 2]
 *
 * // 限制缓存数量。如限制缓存数量为1时,效果同 memoize-one 。
 * const memoizedOneValues = memoize(Object.values, { max: 1 });
 *
 * // 自定义比较函数。如深比较。
 * import { isEqual } from 'ut2'
 * const deepMemoizedValues = memoize(Object.values, { isEqual });
 * const result1 = deepMemoizedValues({ a: 1 });
 * const result2 = deepMemoizedValues({ a: 1 });
 * console.log(result1 === result2); // true
 *
 */
function memoize(func, options) {
    const opts = options || {};
    const max = mathCeil(opts.max || 0);
    const isEqual = typeof opts.isEqual === 'function' ? opts.isEqual : argsEqual;
    const cache = [];
    function memoized(...newArgs) {
        const cacheValue = cache.find((item) => item.lastThis === this && isEqual(item.lastArgs, newArgs));
        if (cacheValue) {
            return cacheValue.lastReturn;
        }
        const lastReturn = func.apply(this, newArgs);
        if (max > 0 && cache.length >= max) {
            cache.shift();
        }
        cache.push({
            lastArgs: newArgs,
            lastThis: this,
            lastReturn
        });
        return lastReturn;
    }
    memoized.clear = function () {
        cache.length = 0;
    };
    return memoized;
}
export default memoize;