memoize.js 2.57 KB
define(['../internal/MapCache'], function(MapCache) {

  /** Used as the `TypeError` message for "Functions" methods. */
  var FUNC_ERROR_TEXT = 'Expected a function';

  /**
   * Creates a function that memoizes the result of `func`. If `resolver` is
   * provided it determines the cache key for storing the result based on the
   * arguments provided to the memoized function. By default, the first argument
   * provided to the memoized function is coerced to a string and used as the
   * cache key. The `func` is invoked with the `this` binding of the memoized
   * function.
   *
   * **Note:** The cache is exposed as the `cache` property on the memoized
   * function. Its creation may be customized by replacing the `_.memoize.Cache`
   * constructor with one whose instances implement the [`Map`](http://ecma-international.org/ecma-262/6.0/#sec-properties-of-the-map-prototype-object)
   * method interface of `get`, `has`, and `set`.
   *
   * @static
   * @memberOf _
   * @category Function
   * @param {Function} func The function to have its output memoized.
   * @param {Function} [resolver] The function to resolve the cache key.
   * @returns {Function} Returns the new memoizing function.
   * @example
   *
   * var upperCase = _.memoize(function(string) {
   *   return string.toUpperCase();
   * });
   *
   * upperCase('fred');
   * // => 'FRED'
   *
   * // modifying the result cache
   * upperCase.cache.set('fred', 'BARNEY');
   * upperCase('fred');
   * // => 'BARNEY'
   *
   * // replacing `_.memoize.Cache`
   * var object = { 'user': 'fred' };
   * var other = { 'user': 'barney' };
   * var identity = _.memoize(_.identity);
   *
   * identity(object);
   * // => { 'user': 'fred' }
   * identity(other);
   * // => { 'user': 'fred' }
   *
   * _.memoize.Cache = WeakMap;
   * var identity = _.memoize(_.identity);
   *
   * identity(object);
   * // => { 'user': 'fred' }
   * identity(other);
   * // => { 'user': 'barney' }
   */
  function memoize(func, resolver) {
    if (typeof func != 'function' || (resolver && typeof resolver != 'function')) {
      throw new TypeError(FUNC_ERROR_TEXT);
    }
    var memoized = function() {
      var args = arguments,
          key = resolver ? resolver.apply(this, args) : args[0],
          cache = memoized.cache;

      if (cache.has(key)) {
        return cache.get(key);
      }
      var result = func.apply(this, args);
      memoized.cache = cache.set(key, result);
      return result;
    };
    memoized.cache = new memoize.Cache;
    return memoized;
  }

  // Assign cache to `_.memoize`.
  memoize.Cache = MapCache;

  return memoize;
});