I've been trying to initialize an object in case of missing properties, in a similar way we would do for a variable by using the OR operator:
var finalValue = myVariable || 'hello there'
I've found plenty replies on how to do this by using the Object.assign() method:
finalObject = Object.assign({}, defaultObject, myObject)
Still, I didn't manage to find a proper solution when it comes to an object with nested data. Here's what I came up to:
var arrayConstructor = [].constructor;
var objectConstructor = ({}).constructor;
var whatIsIt = function(object) {
if (object === null) {
return "null";
} else
if (object === undefined) {
return "undefined";
} else
if (object.constructor === arrayConstructor) {
return "array";
} else
if (object.constructor === objectConstructor) {
return "object";
} else {
return "normal variable";
}
}
var copyWithValidation = function(jsonObject, defaultValues) {
let defaultKeys = Object.keys(defaultValues);
let returnValue = Object.assign({}, defaultValues, jsonObject);
// Check for json object
defaultKeys.map((key) => {
switch (whatIsIt(defaultValues[key])) {
case 'object':
if (!jsonObject.hasOwnProperty(key)) {
jsonObject[key] = {};
}
returnValue[key] = copyWithValidation(jsonObject[key], defaultValues[key]);
break;
case 'array':
if (jsonObject.hasOwnProperty(key)) {
returnValue[key] = [...jsonObject[key]];
} else {
returnValue[key] = [...defaultValues[key]];
}
break;
default:
break;
}
});
return returnValue;
}
// My default object
var def1 = {
label1: '',
label2: '',
label3: '',
sublabels: {
label1: '',
label2: '',
label3: '',
},
sublabels2: {
label1: '',
label2: '',
label3: '',
label4: {
title: '',
subtitle: '',
},
},
sublabels3: {
label1: [],
label2: [],
label3: [],
},
}
// The object we want to initialize
var j1 = {
label1: 'hello1',
label2: 'hello2',
sublabels: {
label2: 'subhello2',
label3: 'subhello3',
},
sublabels3: {
label1: ['subhello1', 'subhello2', 'subhello3'],
label4: {
title: 'Hello there!',
subtitle: 'Hello there again',
},
},
}
// Let's run the script!
let p = copyWithValidation(j1, def1);
console.log(p);
The whole idea is to traverse in the object and initially using the "Object.assign({}, defaultValues, jsonObject)" method to "copy" the attributes for the specific level. After that, I'm checking if there are objects or arrays.
In case of an object, I'm setting {} to the target object (in case the property does not exist) and calling the same copyWithValidation() method inside that object; recursively it will cover all levels.
In case of an array I'm simply using the spread operator. The interesting thing is that this works even for objects as array elements.
Not sure though if there's a more efficient code which would return the same result.
Kudos to Aamir Afridi and Joaquin Keller for using/combining their scripts.