Warum und wann Angular.copy verwenden? (Tiefe Kopie)


136

Ich habe alle von Diensten empfangenen Daten direkt in einer lokalen Variablen, einem Controller oder einem Bereich gespeichert. Was ich für eine flache Kopie halte, ist das richtig?

Example:

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

Kürzlich wurde mir gesagt, ich solle angle.copy verwenden, um eine tiefe Kopie zu erstellen.

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

Die Deep-Copy-Informationen scheinen jedoch auf die gleiche Weise zu funktionieren, wenn sie von meiner Angular-Anwendung verwendet werden. Gibt es bestimmte Vorteile bei der Verwendung einer tiefen Kopie (angle.copy) und können Sie sie mir bitte erklären?


2
Sie müssen angle.copy verwenden, wenn Sie eine Kopie des Objekts benötigen (: D). Wenn Sie ein Objekt von einem Ajax-Aufruf erhalten ($ http, $ resource, ...), müssen Sie es nicht kopieren. Wenn Sie dieses Objekt jedoch in der Ansicht ändern möchten, das ursprüngliche Objekt jedoch in einem Cache aufbewahren möchten, möchten Sie möglicherweise kopieren.
Petr Averyanov

Antworten:


166

Verwenden Sie angle.copy, wenn Sie einer anderen Variablen den Wert eines Objekts oder Arrays zuweisen. Dieserobject Wert sollte nicht geändert werden.

Ohne tiefes Kopieren oder Verwenden von angle.copy werden durch Ändern des Eigenschaftswerts oder Hinzufügen einer neuen Eigenschaft alle Objekte aktualisiert , die auf dasselbe Objekt verweisen.

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
Vielen Dank für die schnelle Antwort, ich liebe die Hilfe und ich glaube ich verstehe. Die einzige Echtzeit, in der angle.copy verwendet werden kann, ist eine wörtliche Kopie. Das heißt, ich sollte es nur verwenden, wenn ich ein Duplikat des Originals benötige, in das ich die Eigenschaften ändern kann. Könnte ich die Informationen in zwei separaten Variablen speichern und ihre Eigenschaften danach separat anpassen, anstatt eine Winkelkopie zu erstellen? Beispiel: $scope.one = response.dataund setzen $scope.two = response.data. Dann mach es $scope.two.addProperty = something. Ich sollte das wahrscheinlich nur testen :), würde aber gerne Community-Einblicke bekommen.
Superman2971

2
Antwort: Nein. Grund: Ändern des Werts für die object propertyAktualisierung des neuen Werts für alle Objekte mit derselben Referenz. Deshalb müssen Sie angular.copy
Sarjan Desai

44

In diesem Fall müssen Sie nicht verwenden angular.copy()

Erklärung :

  • =stellt eine Referenz dar, während angular.copy()ein neues Objekt als tiefe Kopie erstellt wird.

  • Die Verwendung =würde bedeuten, dass das Ändern einer Eigenschaft von response.datadie entsprechende Eigenschaft von ändern würde $scope.exampleoder umgekehrt.

  • Die Verwendung angular.copy()der beiden Objekte würde getrennt bleiben und Änderungen würden sich nicht gegenseitig widerspiegeln.


Einfachste Antwort.
Astitva Srivastava

Am einfachsten zu verstehen. Vielen Dank
Puneet Verma

7

Ich würde sagen, angular.copy(source);in Ihrer Situation ist unnötig, wenn Sie später nicht verwenden, ist es ohne Ziel angular.copy(source, [destination]);.

Wenn ein Ziel angegeben wird, werden alle seine Elemente (für Arrays) oder Eigenschaften (für Objekte) gelöscht und anschließend alle Elemente / Eigenschaften aus der Quelle in das Ziel kopiert.

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


Danke Esko! Ich versuche meinen Kopf gerade zu bekommen. Bedeutet dies einen Vorteil für angle.copy: Wenn einer Variablen bereits Daten zugeordnet sind, ist dies eine sauberere Methode zur Neuzuweisung der Elemente / Eigenschaften?
Superman2971

1
Sie verwenden angular.copy()ein Objekt, um zu verhindern, dass anderer Code es ändert. Das ursprüngliche Objekt wird möglicherweise geändert, aber Ihre Kopie sieht die Änderungen nicht. Sie können die Kopie bei Bedarf wiederherstellen.
Esko

1

Bei Verwendung von angle.copy wird anstelle der Aktualisierung der Referenz ein neues Objekt erstellt und dem Ziel zugewiesen (sofern ein Ziel angegeben ist). Aber es gibt noch mehr. Es gibt diese coole Sache, die nach einer tiefen Kopie passiert.

Angenommen, Sie haben einen Factory-Service mit Methoden zum Aktualisieren von Factory-Variablen.

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

und eine Steuerung, die diesen Dienst verwendet,

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

Wenn das obige Programm ausgeführt wird, lautet die Ausgabe wie folgt:

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

Das Coole an der Verwendung von Winkelkopien ist daher, dass die Referenzen des Ziels bei der Änderung der Werte wiedergegeben werden, ohne dass die Werte erneut manuell zugewiesen werden müssen.


1

Ich weiß, dass es bereits beantwortet wurde, aber ich versuche nur, es einfach zu machen. Angular.copy (Daten) können Sie also für den Fall verwenden, dass Sie Ihr empfangenes Objekt ändern möchten, indem Sie seine ursprünglichen Werte unverändert lassen.

Zum Beispiel: Angenommen, ich habe einen API-Aufruf getätigt und mein originalObj erhalten. Jetzt möchte ich die Werte von api originalObj für einige Fälle ändern, aber ich möchte auch die ursprünglichen Werte, damit ich eine Kopie meines api originalObj erstellen kann in duplicateObj und ändern Sie duplicateObj auf diese Weise. Meine ursprünglichenObj-Werte ändern sich nicht. In einfachen Worten, die Änderung von duplicateObj spiegelt sich in originalObj nicht wider, anders als sich js obj verhält.

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

Ergebnis ist wie ....

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

Ich teile nur meine Erfahrungen hier, ich habe angle.copy () verwendet, um zwei Objekteigenschaften zu vergleichen. Ich habe an einer Reihe von Eingaben ohne Formularelement gearbeitet, mich gefragt, wie ich zwei Objekteigenschaften vergleichen kann, und basierend auf dem Ergebnis muss ich die Schaltfläche Speichern aktivieren und deaktivieren. Also habe ich wie unten verwendet.

Ich habe meinem Dummy-Objekt Benutzerwerte eines ursprünglichen Serverobjekts zugewiesen, um userCopy zu sagen, und habe watch verwendet, um Änderungen am Benutzerobjekt zu überprüfen.

Meine Server-API, die mir Daten vom Server abruft:

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

Ich bin mir nicht sicher, aber der Vergleich zweier Objekte bereitete mir immer Kopfschmerzen, aber mit angle.copy () lief es reibungslos.


-2

Javascript übergibt Variablen by reference, dies bedeutet, dass:

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

Jetzt ist wegen by referenceTeil i[1] und jist auch [1], obwohl nur igeändert wurde. Dies liegt daran, dass j = iJavascript die iVariable nicht kopiert und zuweist, jsondern auf die iVariable verweist j.

Durch die Winkelkopie verlieren wir diese Referenz, was bedeutet:

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

Jetzt ist ihier gleich [1], während jimmer noch gleich [] ist.

Es gibt Situationen, in denen solche copyFunktionen sehr praktisch sind.


1
JavaScript übergibt Objekte als Referenz. Keine Primitiven. Testen Sie Ihren Code.
Oleg

Ja gut, die Idee ist ziemlich dieselbe, obwohl sie bearbeitet wurde
guramidev

1
Und angular.copyist intelligenter als die JSON-Serialisierung, da sie Funktionen verarbeiten kann.
Oleg

Ich wusste nicht, dass ich mich erinnern kann, dass ich auf die Winkelquelle geschaut und nur die JSON-Serialisierung gesehen habe, aber ich habe es erneut überprüft und Sie haben Recht.
Guramidev
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.