为什么以及何时使用 angular.Copy? (深度拷贝)

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

Example:


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

最近我被告知使用 angular.copy 来创建一个深度拷贝。

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

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

230326 次浏览

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

解说 :

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

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

  • 使用 angular.copy(),这两个对象将保持独立,并且更改不会相互反映。

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

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

现在因为 by reference的部分 i是[1] ,而 j也是[1] ,即使只有 i被改变。这是因为当我们说 j = i javascript 不复制 i变量并将其赋给 j,而是通过 j引用 i变量。

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

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

现在 i等于[1] ,而 j仍然等于[]。

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

我会说 angular.copy(source);在你的情况下是不必要的,如果以后你不使用它是没有目的地 angular.copy(source, [destination]);

如果提供了目标,那么它的所有元素(对于数组) 或属性(对于对象)被删除,然后所有 元素/属性从源复制到它。

Https://docs.angularjs.org/api/ng/function/angular.copy

将对象或数组的值赋给另一个变量时使用 Angular 收到,且不应更改该 object值。

不使用 深度拷贝或使用 Angular 收到,更改属性值或添加任何引用同一对象的新属性 更新所有对象

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
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>


<div ng-app="copyExample" ng-controller="ExampleController">
<button ng-click='printToConsole()'>Explain</button>
</div>

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

我将一个原始的服务器对象用户值分配给我的虚拟对象(userCopy) ,并使用 watch 检查对用户对象的更改。

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

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();
});


//initially my save button is disabled because objects are same, once something
//changes I am activating save button


$scope.btnSts = true;
$scope.$watch('user', function(newVal, oldVal) {
console.log($scope.userCopy.name);


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 ()它进行得很顺利。

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

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

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

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

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

当上面的程序运行时,输出如下,

****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 (data) ,方法是保持其原始值不变。

例如: 假设我已经调用了 api 并且得到了我原来的 Obj,现在我想在某些情况下改变 api OrigalObj 的值,但是我也想要原来的值,所以我可以做的是,我可以复制一个我的 api OrigalObj 到 double icateObj 中并且修改 double icateObj,这样我原来的 Obj 值就不会改变了。简而言之,与 js obj 的行为方式不同,double icateObj 的修改不会反映在 OrigalObj 中。

 $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);

结果就像..。

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