Skip to content

Instantly share code, notes, and snippets.

@nopjia
Created April 19, 2019 18:17
Show Gist options
  • Save nopjia/cf01468946c7fc7fee1de3a7d4d25e5d to your computer and use it in GitHub Desktop.
Save nopjia/cf01468946c7fc7fee1de3a7d4d25e5d to your computer and use it in GitHub Desktop.
Creates a new object that watches for changes on its properties
/**
* Callback whenever a property in the object changes
* @callback onChangeCallback
* @param {*} newValue
* @param {*} oldValue
* @param {String} path
*/
/**
* Creates a new object that is watched for changes
* Works recursively as long as children are objects
* Will not work for newly defined properties
*
* NOTE: Returning a new object instead of modifying
* orignal boosts performance by over 20x
*
* @param {Object} obj
* @param {onChangeCallback} callback
* @return {Object}
*/
const onChange = (obj, callback, pathPrefix = "") => {
const newObj = {};
const privateData = {};
const keys = Object.keys(obj);
for (let i = 0; i < keys.length; ++i) {
const key = keys[i];
let value = obj[key];
if (typeof value === "object") {
value = onChange(value, callback, `${key}.`);
}
// save key to privateData
privateData[key] = value;
// replace key with getter/setter pointing to privateData
Object.defineProperty(newObj, key, {
enumerable: true,
get() {
return privateData[key];
},
set(newValue) {
const oldValue = privateData[key];
privateData[key] = newValue;
callback(newValue, oldValue, pathPrefix + key);
},
});
}
return newObj;
};
export default onChange;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment