deepmerge comparisions (v3)

Revision 3 of this benchmark created by Enzo on


Setup

var deepExtend = function (/*obj_1, [obj_2], [obj_N]*/) {
      if (arguments.length < 1 || typeof arguments[0] !== 'object') {
        return false;
      }
    
      if (arguments.length < 2) return arguments[0];
    
      var target = arguments[0];
    
      // convert arguments to array and cut off target object
      var args = Array.prototype.slice.call(arguments, 1);
    
      var key, val, src, clone, tmpBuf;
    
      args.forEach(function (obj) {
        if (typeof obj !== 'object') return;
    
        for (key in obj) {
          if ( ! (key in obj)) continue;
    
          src = target[key];
          val = obj[key];
    
          if (val === target) continue;
    
          if (typeof val !== 'object' || val === null) {
            target[key] = val;
            continue;
          } else if (val instanceof Date) {
            target[key] = new Date(val.getTime());
            continue;
          } else if (val instanceof RegExp) {
            target[key] = new RegExp(val);
            continue;
          }
    
          if (typeof src !== 'object' || src === null) {
            clone = (Array.isArray(val)) ? [] : {};
            target[key] = deepExtend(clone, val);
            continue;
          }
    
          if (Array.isArray(val)) {
            clone = (Array.isArray(src)) ? src : [];
          } else {
            clone = (!Array.isArray(src)) ? src : {};
          }
    
          target[key] = deepExtend(clone, val);
        }
      });
    
      return target;
    }
    
    
    
    
    function deepmerge(target, src) {
        var array = Array.isArray(src);
        var dst = array && [] || {};
    
        if (array) {
            target = target || [];
            dst = dst.concat(target);
            src.forEach(function(e, i) {
                if (typeof dst[i] === 'undefined') {
                    dst[i] = e;
                } else if (typeof e === 'object') {
                    dst[i] = deepmerge(target[i], e);
                } else {
                    if (target.indexOf(e) === -1) {
                        dst.push(e);
                    }
                }
            });
        } else {
            if (target && typeof target === 'object') {
                Object.keys(target).forEach(function (key) {
                    dst[key] = target[key];
                })
            }
            Object.keys(src).forEach(function (key) {
                if (typeof src[key] !== 'object' || !src[key]) {
                    dst[key] = src[key];
                }
                else {
                    if (!target[key]) {
                        dst[key] = src[key];
                    } else {
                        dst[key] = deepmerge(target[key], src[key]);
                    }
                }
            });
        }
    
        return dst;
    }
    
    
    
    merge = (function() {
    
        return function merge(first, second) {
    
                var args = arguments,
                        key, val, src, clone;
    
                if (args.length < 2) return first;
    
    
                if (args.length > 2) {
                        // Remove the first 2 arguments of the arguments and add thoose arguments as merged at the begining
                        Array.prototype.splice.call(args, 0, 2, merge(first, second));
                        // Recursion
                        return merge.apply(this, args);
                }
    
    
                for (key in second) {
    
                        if (!(key in second)) continue;
    
                        src = first[key];
                        val = second[key];
    
                        if (val === first) continue;
    
                        if (typeof val !== 'object' && !Array.isArray(val)) {
                                first[key] = val;
                                continue;
                        }
    
    
                        if ( typeof src !== 'object' || src === null ) {
                                clone = (Array.isArray(val)) ? [] : {};
                                first[key] = merge(clone, val);
                                continue;
                        }
    
    
                        clone = (Array.isArray(val)) ?
    
                                (Array.isArray(src)) ? src : []
                        :
                                (!Array.isArray(src)) ? src : {};
    
    
    
                        first[key] = merge(clone, val);
                }
    
                return first;
        }
    
    })();
    
    
    
    
    syncio={};
    syncio.path=function(a,b){syncio.path.recursive.call({circular:[]},a,b,[])},syncio.path.recursive=function(a,b,c){for(var d in a)if(a.hasOwnProperty(d)){if(c.push(d),0==this.stop)return;this.stop=b(c,a[d],d),a[d]&&"object"==typeof a[d]&&a[d]!==a&&-1==this.circular.indexOf(a[d])&&(this.circular.push(a[d]),syncio.path.recursive.call(this,a[d],b,c)),c.pop()}};
    syncio.getset=function(a,b,c){for(var d=0;d<b.length-1;d++)a=a[b[d]];return arguments.length>2&&(a[b[d]]=c),a[b[d]]};
    
    
    syncio.merge = (function() {
    
        var destiny;
    
        function callback(path, value){
    
                if ( value && typeof value == 'object' )
    
                        value = (Array.isArray( value )) ? [] : {};
    
                syncio.getset(destiny, path, value);
    
        };
    
        return function merge(first, second) {
    
                var args = arguments;
    
                if (args.length > 2) {
                        // Remove the first 2 arguments of the arguments and add thoose arguments as merged at the begining
                        Array.prototype.splice.call(args, 0, 2, merge(first, second));
                        // Recursion
                        return merge.apply(this, args);
                }
    
                destiny = first;
    
                syncio.path(second, callback);
    
                return first;
    
        };
    
    })();

Test runner

Ready to run.

Testing in
TestOps/sec
deepExtend
var obj1={a:11,b:12,arr:[1,2,3,{abc:123}],d:{d1:13,d2:{d21:123,d22:{d221:12,d223:{hola:"hola","static":"static"}}}},f:5,g:123},obj2={b:3,c:5,arr:[567],d:{d2:{d22:{d222:25,d223:{hola:"mundo"}}}}};

deepExtend(obj1, obj2);
ready
deepExtend new obj
var obj1={a:11,b:12,arr:[1,2,3,{abc:123}],d:{d1:13,d2:{d21:123,d22:{d221:12,d223:{hola:"hola","static":"static"}}}},f:5,g:123},obj2={b:3,c:5,arr:[567],d:{d2:{d22:{d222:25,d223:{hola:"mundo"}}}}};

deepExtend({}, obj1, obj2);
ready
syncio.merge
var obj1={a:11,b:12,arr:[1,2,3,{abc:123}],d:{d1:13,d2:{d21:123,d22:{d221:12,d223:{hola:"hola","static":"static"}}}},f:5,g:123},obj2={b:3,c:5,arr:[567],d:{d2:{d22:{d222:25,d223:{hola:"mundo"}}}}};

merge(obj1, obj2);
 
ready
syncio.merge new obj
var obj1={a:11,b:12,arr:[1,2,3,{abc:123}],d:{d1:13,d2:{d21:123,d22:{d221:12,d223:{hola:"hola","static":"static"}}}},f:5,g:123},obj2={b:3,c:5,arr:[567],d:{d2:{d22:{d222:25,d223:{hola:"mundo"}}}}};

merge({}, obj1, obj2);
 
ready
deepmerge
var obj1={a:11,b:12,arr:[1,2,3,{abc:123}],d:{d1:13,d2:{d21:123,d22:{d221:12,d223:{hola:"hola","static":"static"}}}},f:5,g:123},obj2={b:3,c:5,arr:[567],d:{d2:{d22:{d222:25,d223:{hola:"mundo"}}}}};

deepmerge(obj2, obj1);
ready
syncio.merge (path&&getset)
var obj1={a:11,b:12,arr:[1,2,3,{abc:123}],d:{d1:13,d2:{d21:123,d22:{d221:12,d223:{hola:"hola","static":"static"}}}},f:5,g:123},obj2={b:3,c:5,arr:[567],d:{d2:{d22:{d222:25,d223:{hola:"mundo"}}}}};

syncio.merge(obj1, obj2);
 
ready
syncio.merge (path&&getset) new object
var obj1={a:11,b:12,arr:[1,2,3,{abc:123}],d:{d1:13,d2:{d21:123,d22:{d221:12,d223:{hola:"hola","static":"static"}}}},f:5,g:123},obj2={b:3,c:5,arr:[567],d:{d2:{d22:{d222:25,d223:{hola:"mundo"}}}}};

syncio.merge({}, obj1, obj2);
 
ready

Revisions

You can edit these tests or add more tests to this page by appending /edit to the URL.