Skip to content

Instantly share code, notes, and snippets.

@kiruh
Last active August 14, 2019 09:46
Show Gist options
  • Save kiruh/690d544bf77248f27e7b197ff99b4bb5 to your computer and use it in GitHub Desktop.
Save kiruh/690d544bf77248f27e7b197ff99b4bb5 to your computer and use it in GitHub Desktop.
Memoize decorator for ES6
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