2015-10-09 9 views
99

Ich habe alle Daten von Diensten direkt auf lokale Variable, Controller oder Bereich gespeichert. Was ich für eine flache Kopie halte, ist das richtig?Warum und wann angular.copy verwenden? (Deep Copy)

Example: 

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

Kürzlich wurde ich angewiesen, angular.copy zu verwenden, um eine tiefe Kopie zu erstellen.

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

Allerdings scheinen die tiefe Kopie Informationen in der gleichen Art und Weise, wenn sie von meiner Angular Anwendung verwendet zu arbeiten. Gibt es spezielle Vorteile für die Verwendung einer tiefen Kopie (angular.copy) und können Sie sie mir bitte erklären?

+1

U verwenden müssen angular.copy, wenn Sie Kopie des Objekts benötigen (: D). Wenn Sie ein Objekt von einem Jax-Aufruf ($ http, $ resource, ...) erhalten, müssen Sie nicht kopieren. Wenn Sie jedoch dieses Objekt in der Ansicht ändern möchten, aber das ursprüngliche Objekt in einer Art Cache behalten möchten, können Sie es kopieren. –

Antwort

123

Verwendung angular.copy, wenn auf eine andere Variable, und dass object Wert Wert des Objekts oder Array-Zuweisung sollte nicht geändert werden.

Ohne tiefe Kopie oder mit angular.copy, Wert der Eigenschaft ändern oder Hinzufügen einer neuen Eigenschaft Update alle Objekt das gleiche 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, liebe die Hilfe und ich denke, ich verstehe. Die einzige Echtzeit, die angle.copy verwendet, wäre eine wörtliche Kopie. Das heißt, ich sollte es nur verwenden, wenn ich ein Duplikat des Originals benötige, für das ich Eigenschaften ändern kann. ** Könnte ich die Informationen in zwei separaten Variablen speichern und ihre Eigenschaften separat anpassen, anstatt eine angular.copy zu erstellen? ** Beispiel: '$ scope.one = response.data' und $ $ scope.two = response.data '. Dann mach '$ scope.two.addProperty = something'. Ich sollte das wahrscheinlich nur testen :), würde aber gerne Einblick in die Community bekommen. – Superman2971

+2

Ans: Nein. Grund: Der Wert von 'object property' wird geändert, um einen neuen Wert für alle Objekte mit derselben Referenz zu erhalten. Deshalb müssen Sie angular.copy verwenden –

29

In diesem Fall brauchen Sie nichtangular.copy()

Erklärung zu verwenden:

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

  • = Verwendung würde bedeuten, dass eine Eigenschaft des response.data Ändern würde die entsprechende Eigenschaft des $scope.example oder umgekehrt ändern.

  • Mit angular.copy() würden die beiden Objekte getrennt bleiben und Änderungen würden sich nicht widerspiegeln.

+0

Einfachste Antwort. –

+0

Am einfachsten zu verstehen. Danke –

-2

Javascript gibt Variablen by reference, bedeutet dies, dass:

jetzt wegen by reference Teil i ist [1], und j [1] als auch, obwohl nur i geändert wurde. Dies ist, weil, wenn wir sagen, j = i Javascript kopiert nicht die i Variable und zuweisen Sie es j aber Verweise i Variablen über j.

Angular Kopie lässt uns diese Referenz verlieren, was bedeutet:

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

Jetzt i hier gleich zu [1], während j noch gleich auf [].

Es gibt Situationen, in denen eine solche Art von copy Funktionalität sehr praktisch ist.

+1

JavaScript übergibt * Objekte * als Referenz. Nicht Primitive. Testen Sie Ihren Code. – Oleg

+0

Ja gut die Idee ist ziemlich gleich, bearbeitet aber – guramidev

+1

Und 'angular.copy' ist intelligenter, dass JSON-Serialisierung, weil es mit Funktionen umgehen kann. – Oleg

7

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

Wenn ein Ziel vorgesehen ist, alle seine Elemente (arrays) oder Eigenschaften (Objekte) werden gelöscht, und dann werden alle Elemente /Eigenschaften von der Quelle sind, um es kopiert.

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

+0

Danke Esko! Versuche, meinen Kopf gerade zu bekommen. ** Bedeutet dies einen Vorteil für angular.copy: Wenn einer Variablen bereits Daten zugeordnet sind, ist dies eine sauberere Art der Neuzuweisung der Elemente/Eigenschaften? ** – Superman2971

+1

Sie verwenden 'angular.copy()' zu einem Objekt, um zu verhindern, dass anderer Code es ändert. Das ursprüngliche Objekt könnte sich ändern, aber Ihre Kopie sieht die Änderungen nicht. Sie können die Kopie bei Bedarf wiederherstellen. – Esko

1

ich hier meine Erfahrung nur teilen bin, habe ich angular.copy() zwei Objekte Eigenschaften zu vergleichen. Ich arbeitete an einer Reihe von Eingaben ohne Formularelement, ich fragte mich, wie man zwei Objekteigenschaften vergleicht und basierend auf dem Ergebnis muss ich die Schaltfläche zum Speichern aktivieren und deaktivieren. Also habe ich wie folgt benutzt.

Ich habe einem Dummy-Objekt ein original Server-Objekt Benutzerwerte zugewiesen, sagen BenutzerCopy und Used-Uhr, um Änderungen an Benutzerobjekt zu überprüfen.

meine Server-API, die mir Daten vom Server bekommt

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

// zunächst Taste speichern meine ist deaktiviert, da Objekte gleich sind, einmal etwas // Änderungen Ich activing speichern BTN

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

Ich bin mir nicht sicher, aber das Vergleichen von zwei Objekten war wirklich für mich immer wichtig, aber mit angular.copy() ging es sehr schnell.

1

Wenn Sie angular.copy verwenden, wird anstelle des Aktualisierens der Referenz ein neues Objekt erstellt und dem Ziel zugewiesen (sofern ein Ziel angegeben ist). Aber da ist noch mehr. Es gibt dieses coole Ding, das nach einer tiefen Kopie geschieht.

Angenommen, Sie haben einen Factory-Service, der Methoden zur Aktualisierung von Fabrikvariablen enthält.

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,

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

So ist die kühle Sache über die Verwendung von Winkeln Kopie

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

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

sein Ist dies der Fall, werden die Referenzen des Ziels bei der Änderung der Werte berücksichtigt, ohne dass die Werte erneut manuell neu zugewiesen werden müssen.

0

Ich weiß, es ist bereits beantwortet, immer noch versuche ich es einfach zu machen. So angular.copy (Daten) können Sie verwenden, wenn Sie Ihr empfangenes Objekt ändern/ändern möchten, indem Sie seine ursprünglichen Werte unverändert/unverändert beibehalten.

Zum Beispiel: nehme ich api Anruf gemacht und meine originalObj bekam, jetzt habe ich die Werte von api originalObj für einige Fall ändern wollen, aber ich möchte die ursprünglichen Werte zu so, was ich tun kann, kann ich machen eine Kopie meines api originalObj in duplicObj und modify duplicObj so, dass sich meine originalObj Werte nicht ändern. In einfachen Worten, duplicateObj Modifikation wird nicht in originalObj widerspiegeln, wie js obj sich 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"}