Почему и когда использовать angular.copy? (Deep Copy)

Я сохраняю все данные, полученные от служб, прямо к локальной переменной, контроллеру или области видимости. То, что, я полагаю, будет считаться мелкой копией, верно?

Example:

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

Недавно мне сказали использовать angular.copy, чтобы создать глубокую копию.

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

Однако, как представляется, информация о глубокой копии работает аналогично при использовании моего приложения Angular. Есть ли особые преимущества для использования глубокой копии (angular.copy), и можете ли вы объяснить мне это?

Ответ 1

Используйте angular.copy при назначении значения объекта или массива другой переменной, и это значение object не следует изменять.

Без глубокой копии или использования angular.copy, изменения значения свойства или добавления любого нового свойства обновите весь объект, ссылающийся на этот же объект.

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

Ответ 2

В этом случае вам не нужно использовать angular.copy()

Объяснение:

  • = представляет ссылку, тогда как angular.copy() создает новый объект как глубокую копию.

  • Использование = означает, что изменение свойства response.data изменит соответствующее свойство $scope.example или наоборот.

  • Используя angular.copy(), два объекта останутся отдельными, и изменения не будут отражаться друг на друге.

Ответ 3

Я бы сказал, что angular.copy(source); в вашей ситуации не нужно, если позже вы не используете это без адресата angular.copy(source, [destination]);.

Если предоставляется пункт назначения, все его элементы (для массивов) или свойства (для объектов) удаляются, а затем все элементы/свойства из источника скопированы на него.

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

Ответ 4

Я просто делюсь своим опытом здесь, я использовал 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() все прошло гладко.

Ответ 5

При использовании angular.copy вместо обновления ссылки новый объект создается и назначается получателю (если предоставляется пункт назначения). Но там больше. Там эта крутая вещь, которая происходит после глубокой копии.

Скажем, у вас есть служба factory, у которой есть методы, которые обновляют переменные factory.

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 заключается в том, что ссылки адресата отражаются с изменением значений без повторного назначения значений вручную.

Ответ 6

Я знаю, что это уже ответили, все же я просто пытаюсь сделать это простым. Таким образом, angular.copy(data) вы можете использовать в случае, если вы хотите изменить/изменить полученный объект, сохранив его исходные значения неизмененными/неизменными.

Например: предположим, что я сделал вызов API и получил свой originalObj, теперь я хочу изменить значения api originalObj для некоторых случаев, но я также хочу, чтобы исходные значения были такими, что я могу сделать, я могу сделать копию мой api originalObj в duplicateObj и изменить duplicateObj таким образом, мои значения originalObj не изменятся. Проще говоря, модификация duplicateObj не будет отражаться в originalObj в отличие от поведения js obj.

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

Ответ 7

Javascript передает переменные by reference, это означает, что:

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

Теперь из-за by reference part i является [1], а j равно [1], хотя был изменен только i. Это связано с тем, что, когда мы говорим j = i, javascript не копирует переменную i и присваивает ее j, а ссылается на i на переменную j.

Angular копия позволяет нам потерять эту ссылку, что означает:

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

Теперь i здесь равно [1], а j по-прежнему равен [].

Бывают ситуации, когда такая функция copy очень удобна.