Smelly Code

Angular => extend, copy & merge

February 11, 2017👓 4 min

Superheroic AngularJs comes with a set of utility functions which are not specific to angular and can be leveraged anywhere. In this post, we will discuss angular.copy(), angular.extend() & angular.merge(). Before delving into these, we need to walk through two important concepts Deep Copy and Shallow Copy cause these functions linger around these concepts.

Shallow Copy is a field by field copy of an object. All the fields of an object are copied to another object. If a field value is a reference to an object (e.g., a memory address) it copies the reference and if field value is a primitive type it copies the value of the primitive type. Since we copy the reference only so if one object is modified then changes will be visible in other object also.

Deep Copy duplicates everything. In lieu of copying the references, it creates a new copy of object and then copy the refrence of new object to destination object. Since we create a brand new object and refer it. Thus the changes made in one objects are not visible to another object. A detailed discussion on deep copy and shallow copy can be found here.

Well now it’s high time for our celebrated functions. Let’s look into them one by one.

angular.copy() does deep copy of an object. In other words, it creates the new destination object(if not supplied) by duplicating the values from supplied source object.

angular.copy(source, [destination]);

As you can see the second parameter is optional. So when it is not passed a new object is created otherwise properties will be copied to destination object.

var source = { a: 'a', b: 'b' }; var destination = { x: 'my ex', y: 'your y' }; var sourceCopy = angular.copy(source); sourceCopy.a = 'Changed a'; console.log(source.a, sourceCopy.a); //"a", "Changed a"

Here are some cases from the official api doc for angular.copy() which extensively talks about it.

  • If no destination is supplied, a copy of the object or array is created.
  • If a destination is provided, all of its elements (for arrays) or properties (for objects) are deleted and then all elements/properties from the source are copied to it.
  • If source is not an object or array (inc. null and undefined), source is returned.
  • If source is identical to destination an exception will be thrown.

angular.extend() as name suggests it extends the destination object by copying enumerable properties of source object. Let’s see it in action.

var source = { a: 'a' }; var destination = { b: 'b' }; angular.extend(destination, source); console.log(destination); //{a: 'a', b: 'b'} var obj = { c: 'c' }; //if you don't want to mess with original destination obj. var r = angular({}, obj, source); console.log(r); //{a: 'a', c:'c'}

angular.extend() does shallow copy which means if changes are made in non-primitive property of source object than they will be visible in destination object or vice versa.

var source = { a: { c: 'Some value of c' } }; var destination = { b: 'this is b' }; angular.extend(destination, source); console.log(destination); // {a: {c: 'Some value of c'}, b: 'this is b'} source.a.c = 'modified c'; console.log(destination.a.c); // "modified c"

Note: angular.extend() does not support rescursive merge(deep copy). That’s where angular.merge() comes into picture. See the code below.

var objA = { a: { b: 'b' } }; var objB = { a: { c: 'c' } }; var r = angular.extend({}, objA, objB); // It will log { a: { c : "c" } } instead of // { a: { b: "b", c : "c" }} console.log(r);

angular.merge() deeply extends destination object by copying enumerable properties from the source to destination. Unlike extend(), merge() recursively descends into object properties of source and perform copy.

var objA = { a: { b: 'b' } }; var objB = { a: { c: 'c' } }; var r = angular.merge({}, objA, objB); console.log(r); // { a: { b: "b", c : "c" }}

That’s all folks!! Here are the references: angular.extend(), angular.copy() & angular.merge().

Hi, I am Hitesh.