Created
April 19, 2019 18:17
-
-
Save nopjia/cf01468946c7fc7fee1de3a7d4d25e5d to your computer and use it in GitHub Desktop.
Creates a new object that watches for changes on its properties
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
/** | |
* 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