AngularJS:复制 vs 扩展

5

解释:

我们在一些情况下需要将一个对象复制到另一个对象中。在这种情况下,我们可能有两个解决方案: angular.copy()angular.extend().

我面临的挑战:

正如我们所知道的,angular.copy(source, destination)会创建源对象的深层副本并将其分配给目标对象。通过编写深度复制,我们意味着创建了被引用对象的新副本,并且它功能正常。

深度复制代码:

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

在这里,我修改了源对象mySource.name = "Alpha",但是预期中并没有影响到目标对象myDest。 如果我们检查mySource.obj === myDest.obj,会得到false,因为它们指向不同的对象。
现在,我正在使用angular.extend(destination, source)时遇到问题,因为它创建一个浅拷贝,这意味着源和目标都将指向同一个地址。所以,如果我修改源对象,那么它也会反映在目标对象中。但是这并没有发生。 浅拷贝代码:
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/

由于我是新手,需要帮助理解angular.copy()和angular.extend()的正确使用方法。

如有任何紧急帮助将不胜感激。谢谢。

4个回答

11

我更新了代码。现在angular.extends的功能与您预期的一样。请记住,如果您将空对象作为第一个参数(目标)传递给angular.extends,然后再传递源对象,那么angular会保留两个对象并只复制属性,就像angular.copy一样。

// 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

5

angular.copy函数可以克隆(深拷贝)一个对象并创建一个包含相同值的新对象,而angular.extend函数只进行浅拷贝,因此属性引用的是内存中相同的值。在这里有一个非常好的解释,它很好地区别了.copy().extend().merge()方法。


2

原始值是按值复制而不是按引用复制,但首先要理解copy vs extend

copy

迭代对象的每个属性,如果它是原始值,只需复制它,如果它是对象,则创建一个新对象并执行递归复制

实现如下,注意显然还有一些其他情况,但我保持简单

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]
    }
  }
}

扩展

遍历对象的每个属性,如果是基本类型,则直接复制,如果是对象,则创建一个指向原始对象的引用,而不是创建一个具有相同引用的新对象。

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

也许你期望当你进行浅拷贝时,基本类型也会被浅拷贝,然而如上所示,它们总是被克隆的。为了解决这个问题,你应该改变一个引用对象的属性(通过浅拷贝实现)。
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

2
对于对象的副本,以下事项需要注意。
  • 对象是否指向相同的内存位置

  • 普通复制 - 是

  • Angular 复制 - 否

  • Angular 扩展 - 否

  • Angular 合并 - 否

  • 内部对象是否指向相同的内存位置

  • 普通复制 - 是

  • Angular 复制 - 否

  • Angular 扩展 - 否

  • Angular 合并 - 否

  • 复制是否保留当前子对象或删除该对象

  • 普通复制 - 覆盖

  • Angular 复制 - 覆盖

  • Angular 扩展 - 保留

  • Angular 合并 - 保留

这是plunker的副本。

// '=' 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

你的代码表明了一件事情(angular.extend 对于内部对象使用相同的引用),而你的总结则陈述了另一件事情。 - greenoldman
是的。我认为angular.extend应该在“内部对象是否指向相同的内存位置”列表中是“是”。 - Yash Kapila

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接