Search code examples
javascriptobjectangularjsunderscore.jsextend

Nested object extend and skipping undefined properties (in Angular or Underscore)


Is there any implementation (or pattern) on how to handle the following extend cases? AFAIK there's no way to do it straightforward neither in Angular or Underscore, is that right?

Otherwise here's my implementation, but I'd like to know if there's anything that has already been done, or in any case, know your feedback about my code, thanks!

http://jsbin.com/welcome/52916/edit

/**    
Extends the target object with the properties in the source object, with the following special handling:

-   it doesn't extend undefined properties, i.e.
        target: { a: 10 }
        source: { a: undefined }
        result: { a: 10 }

-   it does nested extends rather than overwriting sub-objects, i.e.
        target: { b: { i: 'Hi' } }
        source: { b: { j: 'Bye' } }
        result: { b: { i: 'Hi', j: 'Bye' } }

*/
function extend( target, source ) {
  _.each( _.keys( source ), function( k ) {
    if (angular.isDefined( source[k] )) {
      if (angular.isObject( source[k] )) {
        extend( definedOr( target[k], {} ), source[k] );
      }
      else {
        target[k] = source[k];
      }
    }
  });
  return target;
}

Solution

  • Yes, I guess, neither _.extend nor _.defaults solves your problem and my Angular-Fu is not good enough to comment there.

    But, It does look like jQuery.extend(true, target, source) solves both your use-cases. The true, in the method call does a deep-extend while the extend method already works with the undefined case you mentioned.

    If you need more control over resolving conflicts between source and target objects I have always found that Object.merge(target, source, deep:boolean, resolve:boolean|function) to be more flexible. In case you are wondering that is a method from a library called Sugar.js.

    For the sake of completeness, the Sugar.js method can be used like given below for your particular use-case.

    Object.merge(target, source, true, false);
    

    Hope that answered your question.