如何仅针对 hasOwnProperty false 属性将 Object.assign() 默认值设置为另一个部分完成的 object?

How do I Object.assign() default values to another partly complete object only for hasOwnProperty false properties?

更新问题标题和说明 - 2017 年 2 月 17 日

与默认 object 属性和值相比,是否有一个有效的函数可以填充 object 唯一缺少的属性?

我目前正在开发一个机器人 class,它通过更新网络调用检索 JSON API。 Object.assign(targetObj, sourceObj) 帮了大忙,但想知道是否还有其他类似的方法。

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.
}

我考虑过多个 if 条件 hasOwnProperty 但我想知道是否有比 table if 条件更好的方法,例如 Object.assign()?

我不想为此使用其他脚本或使用 npm。

正如 Julian Soro 在评论中所说,我认为最好的方法是通过 lodash。他们甚至有一个 defaultsDeep 函数

https://lodash.com/docs/4.17.4#defaultsDeep

我一直在浏览我的代码片段并尝试构建我想要的功能。几个小时后我成功了。

Return一个新的目标对象而不伤害原来的。

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

例子

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": ""
    }
}
*/

我不知道是否有更好的编码方式。但如果有,请随时编辑。另外,如果您想知道为什么我不使用 for in 循环方法。这是因为 jslint 现在在 es6 中不鼓励它,我认为我不能禁用警告。