2015-10-09 22 views
99

Ho salvato tutti i dati ricevuti dai servizi direttamente alla variabile locale, al controller o all'ambito. Quello che suppongo sarebbe considerato una copia superficiale, è corretto?Perché e quando usare angular.copy? (Copia profonda)

Example: 

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

Recentemente mi è stato detto di usare angular.copy per creare una copia profonda.

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

Tuttavia, le informazioni di copia profonda sembrano funzionare allo stesso modo quando utilizzate dall'applicazione Angular. Ci sono vantaggi specifici nell'uso di una copia profonda (angular.copy) e puoi spiegarmele per favore?

+1

U bisogno di utilizzare angular.copy se avete bisogno di copia dell'oggetto (: D). Se si riceve oggetto da una chiamata ajax ($ http, $ risorsa, ...) non è necessario copiare. Se invece vuoi modificare questo oggetto in vista, ma tieni l'oggetto originale in una sorta di cache, potresti volere la copia. –

risposta

123

Uso angular.copy quando il valore di oggetto o array a un'altra variabile e che object valore assegnazione non deve essere modificato.

Senza copia completa o utilizzando angular.copy, modificando il valore della proprietà o aggiungere qualsiasi nuovo aggiornamento struttura tutti oggetto referenziare stesso oggetto.

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

Grazie mille per la rapida risposta, amore per l'aiuto e penso di aver capito. L'unico tempo reale per usare angular.copy sarebbe per una copia letterale. Significa che dovrei usarlo solo se ho bisogno di un duplicato dell'originale su cui posso modificare le proprietà. ** Potrei salvare le informazioni su due variabili separate e regolare le loro proprietà separatamente dopo invece di creare un angular.copy? ** Esempio: '$ scope.one = response.data' e impostare' $ scope.two = response.data '. Quindi esegui '$ scope.two.addProperty = something'. Probabilmente dovrei provare solo questo :), ma mi piacerebbe avere una visione della comunità. – Superman2971

+2

Risposta: No. Motivo: la modifica del valore di 'proprietà oggetto' aggiorna il nuovo valore a tutti gli oggetti con lo stesso riferimento. Ecco perché devi usare angular.copy –

29

In tal caso, non è necessario utilizzare angular.copy()

Spiegazione:

  • = rappresenta un punto di riferimento, mentre angular.copy() crea un nuovo oggetto come una copia profonda.

  • Uso = significherebbe che modificando le proprietà di response.data cambierebbe la proprietà corrispondente $scope.example o viceversa.

  • Utilizzando angular.copy() i due oggetti rimarrebbero separati e le modifiche non si rifletterebbero l'una sull'altra.

+0

Risposta più semplice. –

+0

Più facile da capire. Grazie –

-2

Javascript passa variabili by reference, questo significa che:

Ora, a causa della by reference parte i è [1], e j è [1] e, anche se solo i è stato modificato. Questo perché quando diciamo j = i javascript non copia la variabile i e assegnarla a j ma fa riferimento alla variabile i tramite j.

copia angolare ci permette di perdere questo riferimento, il che significa:

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

Ora i qui è uguale a [1], mentre j equivale ancora [].

Ci sono situazioni in cui questo tipo di funzionalità di copy è molto utile.

+1

JavaScript passa * oggetti * per riferimento. Non primitivi Prova il tuo codice – Oleg

+0

Sì, l'idea è praticamente la stessa, modificata anche se – guramidev

+1

E 'angular.copy' è più intelligente della serializzazione JSON perché può gestire le funzioni. – Oleg

7

Direi che angular.copy(source); nella tua situazione non è necessaria se in seguito non la usi senza destinazione angular.copy(source, [destination]);.

Se viene fornita una destinazione, tutti gli elementi (per array) o proprietà (per oggetti) sono soppressi e quindi tutti elementi/oggetti di sorgente vengono copiati ad esso.

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

+0

Grazie Esko! Sto cercando di mettere la testa dritta. ** Significa che un vantaggio per angular.copy sarebbe: se una variabile ha già dati associati ad essa, questo è un modo più pulito di riassegnare gli elementi/proprietà? ** – Superman2971

+1

Si usa 'angular.copy()' per un oggetto per impedire ad altro codice di modificarlo. L'oggetto originale potrebbe cambiare, ma la tua copia non vedrà le modifiche. È possibile ripristinare la copia, se necessario. – Esko

1

Sto solo condividendo la mia esperienza qui, ho usato angular.copy() per confrontare due proprietà degli oggetti. Stavo lavorando su un numero di input senza elemento di modulo, mi chiedevo come confrontare due proprietà di oggetti e in base al risultato devo abilitare e disabilitare il pulsante di salvataggio. Così ho usato come sotto.

Ho assegnato un valore utente dell'oggetto server originale al mio oggetto fittizio, diciamo userCopy e usato watch per controllare le modifiche all'oggetto utente.

mio server API che ottiene mi dati dal server

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

// inizialmente la mia salvare è disattivato perché gli oggetti sono gli stessi, una volta che qualcosa // cambiamenti sto attivando Salva 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); 

Non sono sicuro, ma il confronto tra due oggetti è stato per me sempre un'eccessiva, ma con angular.copy() è andato avanti senza problemi.

1

Quando si utilizza angular.copy, anziché aggiornare il riferimento, viene creato un nuovo oggetto che viene assegnato alla destinazione (se viene fornita una destinazione). Ma c'è di più. C'è questa cosa interessante che succede dopo una copia profonda.

Supponiamo di disporre di un servizio di fabbrica con metodi che aggiornano le variabili di fabbrica.

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

e un controllore che utilizza questo servizio,

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

Quando il programma sopra viene eseguito l'output sarà il seguente,

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

Così la cosa fredda sull'utilizzo copia angolare è che, i riferimenti della destinazione si riflettono con il cambio di valori, senza dover riassegnare manualmente i valori, di nuovo.

0

So che ha già risposto, ma sto solo cercando di renderlo semplice. Quindi angular.copy (dati) che è possibile utilizzare nel caso in cui si desideri modificare/modificare l'oggetto ricevuto mantenendo i valori originali non modificati/invariati.

Ad esempio: Supponiamo che io ho fatto chiamata API e ottenuto il mio originalObj, ora voglio cambiare i valori delle api originalObj per qualche caso, ma voglio che i valori originali troppo così cosa che posso fare è, posso fare una copia di my api originalObj in duplicateObj e modifica duplicateObj in questo modo i miei valori di OriginalObj non cambieranno. In parole semplici la modifica di duplicatoObj non si rifletterà in originalObj a differenza di come si comporta 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); 

Il risultato è come ....

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