-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(memoize): adding new util function to memoize results
- Loading branch information
1 parent
9d2408f
commit c55032d
Showing
4 changed files
with
154 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
import { memoize } from './memoize'; | ||
|
||
describe('memoize', () => { | ||
it('should memoize results based on the first argument given', () => { | ||
const values = memoize((a: number, b: number, c: number) => { | ||
return a + b + c; | ||
}); | ||
|
||
expect(values(1, 2, 3)).toEqual(6); | ||
expect(values(1, 3, 5)).toEqual(6); | ||
}); | ||
|
||
it('should support a `resolver`', () => { | ||
const fn = function(a: number, b: number, c: number): number { | ||
return a + b + c; | ||
}; | ||
const memoized = memoize(fn, fn); | ||
|
||
expect(memoized(1, 2, 3)).toEqual(6); | ||
expect(memoized(1, 3, 5)).toEqual(9); | ||
}); | ||
|
||
it('should use `this` binding of function for `resolver`', () => { | ||
const fn = function(a: number): number { | ||
return a + this.b + this.c; | ||
}; | ||
const memoized = memoize(fn, fn); | ||
const object = { memoized: memoized, b: 2, c: 3 }; | ||
|
||
expect(object.memoized(1)).toEqual(6); | ||
object.b = 3; | ||
object.c = 5; | ||
|
||
expect(object.memoized(1)).toEqual(9); | ||
}); | ||
|
||
it('should check cache for own properties', () => { | ||
const props = [ | ||
'constructor', | ||
'hasOwnProperty', | ||
'isPrototypeOf', | ||
'propertyIsEnumerable', | ||
'toLocaleString', | ||
'toString', | ||
'valueOf' | ||
]; | ||
|
||
function identity<T>(value: T): T { | ||
return value; | ||
} | ||
|
||
const memoized = memoize(identity); | ||
|
||
const values = props.map(value => memoized(value)); | ||
|
||
expect(values).toEqual(props); | ||
}); | ||
|
||
it('should cache the `__proto__` key', () => { | ||
const array = []; | ||
const key = '__proto__'; | ||
|
||
function identity<T>(value: T): T { | ||
return value; | ||
} | ||
|
||
[0, 1].forEach((value, index): void => { | ||
let count = 0; | ||
const resolver = index ? identity : undefined; | ||
|
||
const memoized = memoize(() => { | ||
count++; | ||
return array; | ||
}, resolver); | ||
|
||
const cache = memoized.cache; | ||
|
||
memoized(key); | ||
memoized(key); | ||
|
||
expect(count).toEqual(1); | ||
expect(cache.get(key)).toEqual(array); | ||
expect(cache.delete(key)).toEqual(true); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
import { MemoizeInterface } from './types'; | ||
|
||
/** | ||
* 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 used as the map cache key. The `func` | ||
* is invoked with the `this` binding of the memoized function. | ||
* | ||
* @since 3.1.0 | ||
* @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 memoized function. | ||
* @example | ||
* | ||
* const object = { 'a': 1, 'b': 2 } | ||
* const other = { 'c': 3, 'd': 4 } | ||
* | ||
* const values = memoize(values) | ||
* values(object) | ||
* // => [1, 2] | ||
* | ||
* values(other) | ||
* // => [3, 4] | ||
* | ||
* object.a = 2 | ||
* values(object) | ||
* // => [1, 2] | ||
* | ||
* // Modify the result cache. | ||
* values.cache.set(object, ['a', 'b']) | ||
* values(object) | ||
* // => ['a', 'b'] | ||
*/ | ||
export function memoize(func: Function, resolver?: Function): MemoizeInterface { | ||
const memoized = function(...args: any): MemoizeInterface { | ||
const key = resolver ? resolver.apply(this, args) : args[0]; | ||
const cache = memoized.cache; | ||
|
||
if (cache.has(key)) { | ||
return cache.get(key); | ||
} | ||
const result = func.apply(this, args); | ||
memoized.cache = cache.set(key, result) || cache; | ||
return result; | ||
}; | ||
memoized.cache = new Map(); | ||
return memoized; | ||
} | ||
|
||
/*const memoize = (fn: Function): Function => { | ||
const cache = {}; | ||
return (...args): any => { | ||
const stringifiedArgs = JSON.stringify(args); | ||
const result = (cache[stringifiedArgs] = | ||
typeof cache[stringifiedArgs] === 'undefined' | ||
? fn(...args) | ||
: cache[stringifiedArgs]); | ||
return result; | ||
}; | ||
};*/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters