Search code examples
javascriptnode.jsobjectpropertiesdefault

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


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.


Solution

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