Object [Deep] Merge/Extend in POJS (Plain Ol’ JavaScript)

I know there are a lot of JavaScript libraries that include a method to merge/extend (we’ll call it merge from here on) plain objects, but what if: 1) you’re not using one of those (unlikely these days), or 2) you need to do some object merge magic before one of those handy libraries loads (very possible, and the reason why I wrote this function, which has probably been written thousands of times in the history of JavaScript, but oh well)?

Here’s a native JavaScript function to do just that…
https://gist.github.com/Error601/9a181a0b9f414b752c38

In this example, I’m declaring a named function while also adding it as a method to an “APP” namespace object (you know, for the web app we’re writing).

// make sure we've got our APP namespace object
var APP = APP || {};

(function( undefined ){

    function isObject( obj ){
        return Object.prototype.toString.call(obj) === "[object Object]";
    }

    if (!isObject(APP)) {
        APP = {}
    }

    APP.mergeObjects = function mergeObjects( /* [true ,] objects */ ){

        var args = arguments,
            arg1 = args[0],
            arg2 = args[1] || {},
            len  = args.length,
            deep = false,
            i, arg, output = {};


        // first argument will be output object
        if ( isObject(arg1) ){
            output = arg1;
        }
        // unless set to true
        else if ( arg1.toString() === "true" ){
            deep = true;
            output = arg2;
        }

        // stop here and return the output object
        // if argument length is 0 or 1, or
        // if we're trying to deep merge a single object
        if ( len <= 1 || (len === 2 && deep === true) ){
            return output;
        }

        function processObject( obj ){
            var prop;
            for ( prop in obj ){
                if ( obj.hasOwnProperty(prop) ){
                    if ( deep && isObject(obj[prop]) ){
                        output[prop] = mergeObjects( true, output[prop], obj[prop] );
                    }
                    else {
                        output[prop] = obj[prop];
                    }
                }
            }
        }

        // loop over additional arguments
        for ( i = 1; i < len; i++ ){
            arg = args[i];
            if ( isObject(arg) ) {
                processObject(arg);
            }
        }

        return output;

    };

})();
Advertisements