关于javascript:为什么以及何时使用angular.copy?

Why and when to use angular.copy? (Deep Copy)

我一直将从服务接收到的所有数据直接保存到本地变量、控制器或作用域。我认为这是一个肤浅的复制品,对吗?

1
2
3
4
5
6
Example:

DataService.callFunction()
.then(function(response) {
  $scope.example = response.data;
});

最近有人告诉我使用angular.copy创建一个深度副本。

1
$scope.example = angular.copy(response.data);

然而,当我的角应用程序使用深拷贝信息时,它似乎以同样的方式工作。使用深度拷贝(angular.copy)有什么特别的好处,你能给我解释一下吗?


将对象或数组的值赋给另一个变量时,使用angular.copy,并且不应更改object值。

如果不使用深度复制或angular.copy,则更改属性值或添加任何新属性将更新引用同一对象的所有对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
var app = angular.module('copyExample', []);
app.controller('ExampleController', ['$scope',
  function($scope) {
    $scope.printToConsole = function() {
      $scope.main = {
        first: 'first',
        second: 'second'
      };

      $scope.child = angular.copy($scope.main);
      console.log('Main object :');
      console.log($scope.main);
      console.log('Child object with angular.copy :');
      console.log($scope.child);

      $scope.child.first = 'last';
      console.log('New Child object :')
      console.log($scope.child);
      console.log('Main object after child change and using angular.copy :');
      console.log($scope.main);
      console.log('Assing main object without copy and updating child');

      $scope.child = $scope.main;
      $scope.child.first = 'last';
      console.log('Main object after update:');
      console.log($scope.main);
      console.log('Child object after update:');
      console.log($scope.child);
    }
  }
]);

// Basic object assigning example

var main = {
  first: 'first',
  second: 'second'
};
var one = main; // same as main
var two = main; // same as main

console.log('main :' + JSON.stringify(main)); // All object are same
console.log('one :' + JSON.stringify(one)); // All object are same
console.log('two :' + JSON.stringify(two)); // All object are same

two = {
  three: 'three'
}; // two changed but one and main remains same
console.log('main :' + JSON.stringify(main)); // one and main are same
console.log('one :' + JSON.stringify(one)); // one and main are same
console.log('two :' + JSON.stringify(two)); // two is changed

two = main; // same as main

two.first = 'last'; // change value of object's property so changed value of all object property

console.log('main :' + JSON.stringify(main)); // All object are same with new value
console.log('one :' + JSON.stringify(one)); // All object are same with new value
console.log('two :' + JSON.stringify(two)); // All object are same with new value
1
2
3
4
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js">


  <button ng-click='printToConsole()'>Explain</button>


在这种情况下,您不需要使用angular.copy()

说明:

  • =表示一个引用,而angular.copy()创建一个新对象作为深度复制。

  • 使用=意味着更改response.data的属性将更改$scope.example的相应属性,反之亦然。

  • 使用angular.copy(),两个对象将保持分离,并且变化不会相互反映。


我想说,在你的情况下,如果以后你不使用没有目的地的东西,你就没有必要使用。

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.

https://docs.angularjs.org/api/ng/function/angular.copy网站


我知道它已经回答了,但我只是想让它简单些。复制(数据),你可以在你想修改或改变你接收到的对象的情况下,通过保持其原始值不变。

例如:假设我已经调用了api并得到了originalobj,现在我想在某些情况下更改api originalobj的值,但是我也需要原始值,所以我可以做的是,在duplicateobj中复制我的api originalobj并修改duplicateobj,这样我的originalobj值就不会更改。简单来说,与JS对象的行为不同,DuplicateObj修改不会反映在OriginalObj中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 $scope.originalObj={
            fname:'sudarshan',
            country:'India'
        }
        $scope.duplicateObj=angular.copy($scope.originalObj);
        console.log('----------originalObj--------------');
        console.log($scope.originalObj);
        console.log('-----------duplicateObj---------------');
        console.log($scope.duplicateObj);

        $scope.duplicateObj.fname='SUD';
        $scope.duplicateObj.country='USA';
        console.log('---------After update-------')
        console.log('----------originalObj--------------');
        console.log($scope.originalObj);
        console.log('-----------duplicateObj---------------');
        console.log($scope.duplicateObj);

结果就像……

1
2
3
4
5
6
7
8
9
    ----------originalObj--------------
manageProfileController.js:1183 {fname:"sudarshan", country:"India"}
manageProfileController.js:1184 -----------duplicateObj---------------
manageProfileController.js:1185 {fname:"sudarshan", country:"India"}
manageProfileController.js:1189 ---------After update-------
manageProfileController.js:1190 ----------originalObj--------------
manageProfileController.js:1191 {fname:"sudarshan", country:"India"}
manageProfileController.js:1192 -----------duplicateObj---------------
manageProfileController.js:1193 {fname:"SUD", country:"USA"}

使用angular.copy时,将创建一个新对象并将其指定给目标(如果提供了目标),而不是更新引用。但还有更多。有一件很酷的事发生在深度复制之后。

假设您有一个工厂服务,它有更新工厂变量的方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
angular.module('test').factory('TestService', [function () {
    var o = {
        shallow: [0,1], // initial value(for demonstration)
        deep: [0,2] // initial value(for demonstration)
    };
    o.shallowCopy = function () {
        o.shallow = [1,2,3]
    }
    o.deepCopy = function () {
        angular.copy([4,5,6], o.deep);
    }
    return o;
}]);

以及使用此服务的控制器,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
angular.module('test').controller('Ctrl', ['TestService', function (TestService) {
     var shallow = TestService.shallow;
     var deep = TestService.deep;

     console.log('****Printing initial values');
     console.log(shallow);
     console.log(deep);

     TestService.shallowCopy();
     TestService.deepCopy();

     console.log('****Printing values after service method execution');
     console.log(shallow);
     console.log(deep);

     console.log('****Printing service variables directly');
     console.log(TestService.shallow);
     console.log(TestService.deep);
}]);

当上述程序运行时,输出如下:

1
2
3
4
5
6
7
8
9
10
11
****Printing initial values
[0,1]
[0,2]

****Printing values after service method execution
[0,1]
[4,5,6]

****Printing service variables directly
[1,2,3]
[4,5,6]

因此,使用角度复制很酷的一点是,目标的引用会随着值的变化而反映出来,而不必再次手动重新分配值。


我只是在这里分享我的经验,我使用angular.copy()比较两个对象的属性。我正在处理一些没有表单元素的输入,我想知道如何比较两个对象的属性,并根据结果启用和禁用"保存"按钮。所以我用了如下。

我给我的虚拟对象分配了一个原始的服务器对象用户值,比如usercopy,并使用watch检查对用户对象的更改。

从服务器获取数据的服务器API

1
2
3
4
5
6
7
8
9
10
11
12
var req = {
                method: 'GET',
                url: 'user/profile/'+id,
                headers: {'Content-Type': 'application/x-www-form-urlencoded'}
            }
            $http(req).success(function(data) {
                    $scope.user = data;
                    $scope.userCopy = angular.copy($scope.user);
                    $scope.btnSts=true;
            }).error(function(data) {
                $ionicLoading.hide();
            });

//最初,由于对象相同,"保存"按钮被禁用,一旦发生更改,我将激活"保存"btn

1
2
3
4
5
6
7
8
9
10
11
12
13
$scope.btnSts=true;
$scope.$watch('user', function(newVal, oldVal){
    console.log($scope.userCopy.name);
    console.log();
    if ($scope.userCopy.name !== $scope.user.name || $scope.userCopy.email !== $scope.user.email ) {
        console.log('changed');
        $scope.btnSts=false;
    }else{
        console.log('unchanged');
        $scope.btnSts=true;
    }

}, true);

我不确定,但对我来说,比较两个对象确实令人头晕目眩,但对angular.copy()来说,这是令人窒息的。


javascript传递变量by reference,这意味着:

1
2
3
var i = [];
var j = i;
i.push( 1 );

现在,由于by reference部分,i为〔1〕,j也为〔1〕,尽管只改变了i。这是因为当我们说j = ijavascript不复制i变量并将其赋给j变量,而是通过j引用i变量。

角度复制让我们失去这个参考,这意味着:

1
2
3
var i = [];
var j = angular.copy( i );
i.push( 1 );

这里的i等于[1],而j仍然等于[]。

在某些情况下,这种copy功能非常方便。