为具有嵌套数据的对象设置默认值

时间:2020-07-10 19:00:21

标签: javascript node.js object

我一直在尝试在缺少属性的情况下初始化对象,这与我们使用OR运算符对变量的处理方式类似:

var finalValue = myVariable || 'hello there'

我已经找到了很多有关使用Object.assign()方法执行此操作的答复:

finalObject = Object.assign({}, defaultObject, myObject)

不过,当涉及到带有嵌套数据的对象时,我仍然没有找到合适的解决方案。这是我想到的:

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);

整个想法是遍历对象,并且最初使用“ Object.assign({},defaultValues,jsonObject)”方法“复制”特定级别的属性。之后,我要检查是否存在对象或数组。

对于对象,我将{}设置为目标对象(如果属性不存在),然后在该对象内调用相同的copyWithValidation()方法;递归将覆盖所有级别。

在数组的情况下,我只是使用散布运算符。有趣的是,这甚至适用于作为数组元素的对象。

不确定是否有更有效的代码可以返回相同的结果。

Aamir AfridiJoaquin Keller的使用/组合脚本表示敬意。

1 个答案:

答案 0 :(得分:0)

您可以使用递归来定位嵌套。要注意的是,模板不包含sublabels3.label4属性,而数据对象却包含sublabels3.label4属性。该代码配置为在发生这种情况时添加缺少的属性。

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',
        },
    },
}

function initializer(data,template) {
    return Object.entries(data).reduce((initialized, [key, value]) =>{
        if(typeof value === "object" && !Array.isArray(value)){
            initialized[key] = initializer(value, initialized[key] || {}) 
            return initialized
        } else {
            initialized[key] = value;
            return initialized
        }      
    },template)
}

console.log(initializer(j1,def1))