Чому і коли використовувати angular.copy? (Глибока копія)


136

Я зберігав усі дані, отримані від служб безпосередньо, до локальної змінної, контролера чи області. Я вважаю, що це було б мілкою копією, чи правильно це?

Example:

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

Нещодавно мені сказали використовувати angular.copy для створення глибокої копії.

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

Однак, інформація про глибоку копію, здається, працює так само, коли використовується моєю програмою Angular. Чи є конкретні переваги використання глибокої копії (angular.copy) і чи можете ви мені пояснити їх?


2
Вам потрібно використовувати angular.copy, якщо вам потрібна копія об'єкта (: D). Якщо ви отримуєте об'єкт від ajax call ($ http, $ resource, ...), копіювати не потрібно. Якщо ви хочете змінити цей об’єкт у поданому вигляді, але зберегти оригінальний об'єкт у якомусь кеші, вам може знадобитися його копія.
Петро Авер’янов

Відповіді:


166

Використовуйте 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'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>


1
Дуже дякую за швидку відповідь, люблю допомогу, і я думаю, що я розумію. Єдиний реальний час використання angular.copy - це буквальна копія. Значення, я повинен використовувати його лише у тому випадку, якщо мені потрібен дублікат оригіналу, на який я можу змінити властивості. Чи можу я зберегти інформацію до двох окремих змінних і відрегулювати їх властивості окремо після того, як зробити angular.copy? Приклад: $scope.one = response.dataі встановити $scope.two = response.data. Тоді робіть $scope.two.addProperty = something. Я, мабуть, повинен просто перевірити це :), але хотів би ознайомитись із громадою.
Superman2971

2
Відповідь: Ні. Причина: зміна значення object propertyоновлення нового значення для всіх об'єктів, що мають однакове посилання. Ось чому вам доведеться скористатися angular.copy
Sarjan Desai

44

У такому випадку вам не потрібно користуватися angular.copy()

Пояснення :

  • =являє собою посилання, тоді як angular.copy()створює новий об'єкт у вигляді глибокої копії.

  • Використання =означало б, що зміна властивості of response.dataби змінила відповідне властивість $scope.exampleабо навпаки.

  • Використання angular.copy()двох об'єктів залишатиметься окремим, і зміни не відображатимуться один на одному.


Найпростіша відповідь.
Astitva Srivastava

Найпростіше зрозуміти. Спасибі
Пунет Верма

7

Я б сказав, що angular.copy(source);у вашій ситуації непотрібно, якщо пізніше ви не використовуєте це без призначення angular.copy(source, [destination]);.

Якщо призначення призначене, всі його елементи (для масивів) або властивості (для об'єктів) видаляються, а потім всі елементи / властивості з джерела копіюються в нього.

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


Дякую Еско! Намагаюсь прямо підняти голову. Чи означає це, що користь для angular.copy буде такою: якщо змінна вже має пов’язані з нею дані, це більш чистий спосіб перепризначення елементів / властивостей?
Superman2971

1
Ви використовуєте angular.copy()об'єкт, щоб запобігти його зміні іншим кодом. Оригінальний об’єкт може змінитися, але ваша копія не побачить цих змін. Ви можете відновити копію за потреби.
Есько

1

Під час використання 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]

Таким чином, прикольна річ у використанні кутової копії полягає в тому, що посилання пункту призначення відображаються зі зміною значень, без необхідності повторного присвоєння значень вручну.


1

Я знаю, що його вже відповіли, я все ще намагаюся зробити це просто. Отже, angular.copy (дані) ви можете використовувати у випадку, коли ви хочете змінити / змінити отриманий об’єкт, зберігаючи його вихідні значення незміненими / незмінними.

Наприклад: припустимо, я здійснив дзвінок 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"}

1

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


-2

Javascript передає змінні by reference, це означає, що:

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

Тепер через by referenceчастину iє [1], і jє [1], навіть якщо тільки iбуло змінено. Це тому, що, коли ми кажемо, j = iJavaScript не копіює iзмінну і не присвоює їй, jа посилання на iзмінну черезj .

Кутова копія дозволяє нам втратити цю посилання, що означає:

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

Тепер iтут дорівнює [1], аj ще дорівнює [].

Бувають ситуації, коли подібний copyфункціонал дуже зручний.


1
JavaScript передає об'єкти за посиланням. Не примітиви. Перевірте свій код.
Олег

Так, ідея майже така ж, відредагована
guramidev

1
І angular.copyбільш розумною є серіалізація JSON, оскільки вона може мати справу з функціями.
Олег

Я не знав цього, я міг поклястись, що пам’ятаю, що дивився на кутове джерело і бачив лише серіалізацію JSON, але я перевірив це ще раз, і ти маєш рацію.
guramidev
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.