Updated Question Title & Description - 17th February 2017
Is there an effective function that fills an object's only missing properties compared to a default object properties and values?
I'm currently working on a bot class that retrieves a JSON API by update web calls. Object.assign(targetObj, sourceObj)
has helped a lot but wondering if there was another method like it.
function (result) {
// default properties if they don't exist inside result object
const defaults = {
from: {
id: NaN,
username: ""
}
};
// Example "from" may not exist at all in the result object.
// Maybe "from" does exist in result and provides only an "id",
// but I don't want to overwrite the "id" and still provide
// the "username" with a default value if there isn't one.
}
I thought about multiple if conditioning hasOwnProperty
but I'm wondering is there a better way than a table of if conditions like Object.assign()?
I don't want to require another script or use npm for this.
I've been going through my code snippets and trying to build the functionality I wanted. I've managed to succeed after many hours.
Return a new target object without harming the original.
function defaultsDeep(target, defaults) {
var clone = JSON.parse(JSON.stringify(target));
function run(clone, defaults) {
const DEFAULTS_PROPERTY_NAMES = Object.getOwnPropertyNames(defaults);
DEFAULTS_PROPERTY_NAMES.forEach(function (property) {
if (Object.prototype.toString.call(defaults[property]) === "[object Object]") {
if (!clone.hasOwnProperty(property)) {
clone[property] = {};
}
run(clone[property], defaults[property]);
} else if (!clone.hasOwnProperty(property)) {
clone[property] = defaults[property];
}
});
}
run(clone, defaults);
return clone;
}
Example
var result = {
"message_id": 1,
"from": {
"id": 12345
}
};
const defaults = {
"from": {
"id": null,
"username": ""
}
};
var newObj = defaultsDeep(result, defaults);
console.log("newObj " + JSON.stringify(newObj));
/* result
{
"message_id": 1,
"from": {
"id": 12345,
"username": ""
}
}
*/
I don't know if there's a better way of coding this. But if there is, feel free to edit. Also, if you're wondering why I didn't use for in
loop method. It's because jslint discourages it now in es6 and I don't think I can disable the warning.