Last active
August 14, 2019 09:46
-
-
Save kiruh/690d544bf77248f27e7b197ff99b4bb5 to your computer and use it in GitHub Desktop.
Memoize decorator for ES6
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
let disabled = false; | |
let disabledMap = new WeakMap(); | |
let storage = new WeakMap(); | |
const hasMemoizedProperty = (obj, propName) => { | |
if (!storage.has(obj)) storage.set(obj, {}); | |
const props = storage.get(obj); | |
if (propName in props) return true; | |
return false; | |
}; | |
const getMemoizedProperty = (obj, propName) => { | |
if (!storage.has(obj)) storage.set(obj, {}); | |
const props = storage.get(obj); | |
if (propName in props) return props[propName]; | |
return undefined; | |
}; | |
const setMemoizedProperty = (obj, propName, value) => { | |
if (!storage.has(obj)) storage.set(obj, {}); | |
const props = storage.get(obj); | |
props[propName] = value; | |
}; | |
const handleMemoizedProperty = (obj, propName, func) => { | |
if (disabled || disabledMap.has(obj)) return func.call(obj); | |
if (!hasMemoizedProperty(obj, propName)) { | |
const value = func.call(obj); | |
setMemoizedProperty(obj, propName, value); | |
} | |
return getMemoizedProperty(obj, propName); | |
}; | |
const memoizeGetter = (target, args) => { | |
const { key, descriptor } = target; | |
const { get } = descriptor; | |
return { | |
...target, | |
descriptor: { | |
...descriptor, | |
get() { | |
return handleMemoizedProperty(this, key, get, args); | |
} | |
} | |
}; | |
}; | |
const memoizeMethod = (target, args) => { | |
const { key, descriptor } = target; | |
if (descriptor.value.length > 0) { | |
throw new Error( | |
"@memoize decorator can only be applied to methods of zero arguments" | |
); | |
} | |
const { value } = descriptor; | |
return { | |
...target, | |
descriptor: { | |
...descriptor, | |
value() { | |
return handleMemoizedProperty(this, key, value, args); | |
} | |
} | |
}; | |
}; | |
const memoizeInner = (target, args) => { | |
const { descriptor } = target; | |
if (typeof descriptor.value === "function") { | |
return memoizeMethod(target, args); | |
} | |
if (typeof descriptor.get === "function") { | |
return memoizeGetter(target, args); | |
} | |
throw new Error( | |
`@memoize decorator can be applied to methods or getters, got ${String( | |
descriptor.value | |
)} instead` | |
); | |
}; | |
/* | |
memoize can be applied for methods of zero arguments and getters | |
@memoize | |
func() { | |
// ... | |
} | |
@memoize | |
get prop() { | |
// ... | |
} | |
*/ | |
const memoize = (...args) => { | |
const [target] = args; | |
// @memoize | |
if (target && target.descriptor) return memoizeInner(target); | |
// @memoize(...args) | |
return _target => memoizeInner(_target, args); | |
}; | |
const clear = obj => { | |
if (obj) storage.set(obj, undefined); | |
else storage = new WeakMap(); | |
}; | |
const disable = obj => { | |
if (obj) disabledMap.set(obj, true); | |
else disabled = true; | |
}; | |
const enable = obj => { | |
if (obj) disabledMap.set(obj, false); | |
else { | |
disabled = false; | |
disabledMap = new WeakMap(); | |
} | |
}; | |
export { clear, disable, enable }; | |
export default memoize; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment