AngularJS : copy vs extend
Asked Answered
E

4

5

Explanation :

we come across some situation in which we need to copy one object to another object. In that case, we probably have two solutions: angular.copy() or angular.extend().

Challenge i am facing :

As we know angular.copy(source, destination) creates a deep copy of source object and assign it to destination. By writing deep copy, we mean that a new copy of the referred object is made and its working fine.

deep copy code :

var mySource = {'name' : 'Beta', 'age' : '24'}
var myDest = {}
angular.copy(mySource,myDest);
mySource.name = "Alpha";
console.log(mySource); // Object {name: "Alpha", age: "24"}
console.log(myDest); // Object {name: "Beta", age: "24"}
console.log(mySource.obj === myDest.obj); // false

Here, I modify the source object mySource.name = "Alpha" but it is not affecting the destination object myDest as expected. If we check mySource.obj === myDest.obj, this will give false because both point to different objects.

Now,I am facing issue with angular.extend(destination, source) as it creates a shallow copy means in this both source and destination will point to same address. So, if i will modify source object then it will also reflect in destination object. But it's not happening.

shallow copy code :

var mySource = {'name' : 'Beta', 'age' : '24'}
var myDest = {}
angular.extend(myDest,mySource);
mySource.name = "Alpha";
console.log(mySource); // Object {name: "Alpha", age: "24"}
console.log(myDest); // Object {name: "Beta", age: "24"}
console.log(mySource.obj === myDest.obj); // True

jsfiddle : https://jsfiddle.net/U3pVM/24322/

As i am new in this, need help to understand the proper flow of angular.copy() & angular.extend().

Any immediate help will be highly appreciable. Thanks

Etymon answered 24/4, 2016 at 19:28 Comment(0)
R
11

I updated the code . Now angular.extends works as you expected. Remember that if you pass angular.extends an empty object as first parameter (destination) and then the source, angular is going to preserve both objects and copy only the properties, just like angular.copy does.

// angular.copy()

var mySource = {'name' : 'sakshi', 'age' : '24', 'obj' :{'key':'value'}}
var myDest = angular.copy(mySource);

mySource.name = "Beta";
console.log(mySource); // Object {name: "Beta", age: "24", obj: Object}
console.log(myDest); // Object {name: "sakshi", age: "24", obj: Object}
console.log(mySource.obj === myDest.obj); // false

// angular.extend()

var mySource = {'name' : 'sakshi', 'age' : '24', 'obj' :{'key':'value'}}
var myDest = angular.extend(mySource);
mySource.name = "Beta";
console.log(mySource); // Object {name: "Beta", age: "24", obj: Object}
console.log(myDest); // Object {name: "Beta", age: "24", obj: Object}
console.log(mySource.obj === myDest.obj); // True
Rawdan answered 24/4, 2016 at 19:49 Comment(0)
A
5

agular.copy clones (deep copy) an object and creates a new object using the same values, while angular.extend does a shallow copy so that the attributes refer to same values in memory. A very nice explanation is given here which differentiates very well between .copy(), .extend() and .merge() methods

Ansermet answered 24/4, 2016 at 19:49 Comment(0)
S
2

Primitives are copied by value instead of by reference but first try to understand copy vs extend

copy

Iterates each property of an object, if it's a primitive just copy it, if it's an object create a new object and perform a recursive copy

The implementation may looks as follows, note that obviously there are some additional cases but I'm keeping it simple

function copy(dest, source) {
  for (var property in source) {
    if (typeof source[property] === 'object') {
      var clone = {}
      copy(clone, source[property])
      dest[property] = clone
    } else {
      // a primitive
      dest[property] = source[property]
    }
  }
}

extend

Iterates each property of an object, if it's a primitive just copy it, if it's an object create a reference to the object instead of creating a new object which has the same references as the original object

function extend(dest, source) {
  for (var property in source) {
    dest[property] = source[property]
  }
}

Perhaps you're expecting that when you do a shallow copy primitives will also be shallow copied however as you see above they're always cloned, to solve your problem you should instead change properties of a referenced object (achieved with a shallow copy)

var mySource = {person: {'name' : 'Beta', 'age' : '24'}}
var myDest = {}
angular.extend(myDest,mySource);
mySource.person.name = "Alpha";
console.log(mySource); // Object {person: {name: "Alpha", age: "24"}}
console.log(myDest);  // Object {person: {name: "Alpha", age: "24"}}
console.log(mySource.obj === myDest.obj); // True
Syncopated answered 24/4, 2016 at 19:58 Comment(0)
C
2

For the copy of the object the following things metters.

  • Object points to same memory location or not

  • Normal copy - Yes

  • Angular copy - No

  • Angular extend - No

  • Angular merge - No

  • Inner object points to the same memory location or not

  • Normal copy - Yes

  • Angular copy - No

  • Angular extend - No

  • Angular merge - No

  • Does copy keep the current child objects or remove that objects

  • Normal copy - Override

  • Angular copy - Override

  • Angular extend - Keep

  • Angular merge - Keep

Here is the plunker copy for that

// '=' assignment copy
console.info('assignment copy');
var mySource = {'name' : 'sakshi', 'age' : '24', 'obj' :{'key':'value'}}
var myDest = {oldObj:'old'} //old properties will be override
myDest = mySource;
mySource.name = "Beta";
console.log(mySource); // Object {name: "Beta", age: "24", obj: Object}
console.log(myDest); // Object {name: "sakshi", age: "24", obj: Object}
console.log(mySource === myDest); // true         //points to same object
console.log(mySource.obj === myDest.obj); // true //points to same object


// angular.copy()
console.info('angular copy');
var mySource = {'name' : 'sakshi', 'age' : '24', 'obj' :{'key':'value'}}
var myDest = {oldObj:'old'} //old properties will be override
angular.copy(mySource,myDest);
mySource.name = "Beta";
console.log(mySource); // Object {name: "Beta", age: "24", obj: Object}
console.log(myDest); // Object {name: "sakshi", age: "24", obj: Object}
console.log(mySource === myDest); // false //points to different object
console.log(mySource.obj === myDest.obj); // false //points to different object

// angular.extend()
console.info('angular extend');
var mySource = {'name' : 'sakshi', 'age' : '24', 'obj' :{'key':'value'}}
var myDest = {oldObj:'old'}
angular.extend(myDest,mySource);
mySource.name = "Beta";
console.log(mySource); // Object {name: "Beta", age: "24", obj: Object}
console.log(myDest); // Object {oldObj:'old',name: "sakshi", age: "24", obj: Object}
mySource.obj.key = '123';
console.log(myDest.obj.key);
console.log(mySource === myDest); // false //points to different object
console.log(mySource.obj === myDest.obj); // True //points to same object

// angular.extend()
console.info('angular merge');
var mySource = {'name' : 'sakshi', 'age' : '24', 'obj' :{'key':'value'}}
var myDest = {oldObj:'old'}
angular.merge(myDest,mySource);
mySource.name = "Beta";
console.log(mySource); // Object {name: "Beta", age: "24", obj: Object}
console.log(myDest); // Object {oldObj:'old',name: "sakshi", age: "24", obj: Object}
console.log(mySource === myDest); // false //points to different object
console.log(mySource.obj === myDest.obj); // false //points to different object
Chauchaucer answered 24/4, 2016 at 20:24 Comment(2)
Your code shows one thing (angular.extend uses the same references for the inner objects), and your summary states the other thing.Felspar
Yes. I think angular.extend should be 'Yes' in the 'Inner object points to the same memory location or not' list.Fonzie

© 2022 - 2024 — McMap. All rights reserved.