Search code examples
javascriptunderscore.jsextend

Underscore JS extend object with non-null values from new object


I would like to do something like...

_.extend(original, fresh);

But only to copy over attributes that are not null, so...

var original = {a:1, b:2, c:3}
var fresh = {a:5, b:null}

var mixed = _.extend(original, fresh)
// currently mixed is {a:5,b:null,c:3}
// I want it to be {a:5,b:2,c:3}

Updates

I made some progress, but it does not work with nested objects...

http://jsfiddle.net/billymoon/2GwMx/1/

var original = {a:1, b:2, c:3, d:{g:1}}
var fresh = {a:5, b:null,c:"", d:{e:4,f:5,g:null}}

var mixed = _.extend( original, _.reduce(fresh,function(a,v,k){ 
     if(v){ a[k]=v; } 
     return a; 
}, {}) )

// currently mixed is {"a":5,"b":2,"c":3,"d":{"e":4,"f":5,"g":null}}
// I want it to be {"a":5,"b":2,"c":3,"d":{"e":4,"f":5,g:1}}
alert(JSON.stringify(mixed))

Solution

  • A touch of javascript with a dash of underscore:

    _.mixin({
      extendNonNull: function(obj) {
        _.each(_.rest(arguments,1), function(source) {
          if (source) {
            for (var prop in source) {
              if( _.isObject(source[prop]) && _.isObject(obj[prop])){
                 obj[prop] = _.extendNonNull(obj[prop], source[prop]);
              }
              else if( !_.isNull(source[prop])){
                 obj[prop] = source[prop];
              }
            }
          }
        });
        return obj;
      }
    });
    
    var original = {a:1, b:2, c:3, d:{g:1}};
    var fresh = {a:5, b:null,c:"", d:{e:4,f:5,g:null}};
    
    var mixed = _.extendNonNull(original, fresh);