Deep Extend Idea

by a_robson

HTML

<script src="http://documentcloud.github.com/underscore/underscore.js"></script>

JavaScript

var slice = Array.prototype.slice;
if ( !_.deepExtend ) {
    var behavior = {
        "*": function( obj, sourcePropKey, sourcePropVal ) {
            obj[ sourcePropKey ] = sourcePropVal;
        },
        "object": function(obj, sourcePropKey, sourcePropVal ) {
            obj[ sourcePropKey ] = deepExtend( obj[ sourcePropKey ] || {}, sourcePropVal );
        },
        "array": function( obj, sourcePropKey, sourcePropVal ) {
            var tmp = obj[ sourcePropKey ];
            obj[ sourcePropKey ] = _.filter( _.union( tmp, sourcePropVal ), function( x ) {
                return x;                
            } );
        }
    },
    getActualType = function( val ) {
        if ( _.isArray( val ) ) {
            return "array";
        }
        if ( _.isDate( val ) ) {
            return "date";
        }
        if ( _.isRegExp( val ) ) {
            return "regex";
        }
        return typeof val;
    },
    getHandlerName = function( val ) {
        var propType = getActualType( val );
        return behavior[ propType ] ? propType : "*";
    },
    deepExtend = function( obj ) {
        _.each( slice.call( arguments, 1 ), function( source ) {
            _.each( source, function( sourcePropVal, sourcePropKey ) {
                behavior[ getHandlerName( sourcePropVal ) ]( obj, sourcePropKey, sourcePropVal );
            });
        });
        return obj;
    };

    _.mixin( {
        deepExtend: deepExtend
    } );
}

var objA = {
    config: {
        messaging: {
                exchange: "machina.test",
                topic: "fsm",
                provider: "your mom",
                list: [ "MOM JEAN FACE" ]        
        }
    }
};
var objB = {
    config: {
        messaging: {
            provider: "postal",
            list: [ "GINGER BALLS" ]        
        }
    }
};

document.write("<pre>" + JSON.stringify(_.deepExtend({}, objA, objB), null, 4) + "</pre>");