Mengapa dan kapan menggunakan angular.copy? (Salinan Dalam)

137

Saya telah menyimpan semua data yang diterima dari layanan langsung ke variabel lokal, pengontrol, atau cakupan. Apa yang saya kira akan dianggap salinan dangkal, apakah itu benar?

Example:

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

Baru-baru ini saya diberitahu untuk menggunakan angular.copy untuk membuat salinan dalam.

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

Namun, informasi salinan dalam tampaknya bekerja dengan cara yang sama saat digunakan oleh aplikasi Angular saya. Apakah ada manfaat khusus menggunakan deep copy (angular.copy) dan dapatkah Anda menjelaskannya kepada saya?

Superman2971
sumber
2
Anda perlu menggunakan angular.copy jika Anda membutuhkan salinan objek (: D). Jika Anda menerima objek dari panggilan ajax ($ http, $ resource, ...) tidak perlu menyalin. Namun, jika Anda ingin mengubah objek ini dalam tampilan, tetapi menyimpan objek asli di semacam cache, Anda mungkin perlu menyalin.
Petr Averyanov

Jawaban:

168

Gunakan angular.copy saat menetapkan nilai objek atau larik ke variabel lain dan objectnilai itu tidak boleh diubah.

Tanpa deep copy atau menggunakan angular.copy , mengubah nilai properti atau menambahkan properti baru, perbarui semua objek yang mereferensikan objek yang sama.

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>

Sarjan Desai
sumber
1
Terima kasih banyak atas tanggapan yang cepat, suka bantuannya dan saya rasa saya mengerti. Satu-satunya waktu nyata untuk menggunakan angular.copy adalah untuk salinan literal. Artinya saya hanya boleh menggunakannya jika saya membutuhkan duplikat dari aslinya yang dapat saya ubah propertinya. Bisakah saya menyimpan informasi ke dua variabel terpisah dan menyesuaikan propertinya secara terpisah setelah daripada membuat angular.copy? Contoh: $scope.one = response.datadan set $scope.two = response.data. Lalu lakukan $scope.two.addProperty = something. Saya mungkin harus menguji ini :) tetapi ingin mendapatkan wawasan komunitas.
Superman2971
2
Jwb: Tidak. Alasan: Mengubah nilai object propertyupdate nilai baru ke semua objek yang memiliki referensi yang sama. Itu sebabnya Anda harus menggunakan angular.copy
Sarjan Desai
45

Dalam hal ini, Anda tidak perlu menggunakan angular.copy()

Penjelasan :

  • =mewakili referensi angular.copy()sekaligus membuat objek baru sebagai salinan dalam.

  • Menggunakan =berarti bahwa mengubah properti dari response.dataakan mengubah properti terkait $scope.exampleatau sebaliknya.

  • Menggunakan angular.copy()dua objek akan tetap terpisah dan perubahan tidak akan tercermin satu sama lain.

Nicolas2bert
sumber
Jawaban paling sederhana.
Astitva Srivastava
Paling mudah dimengerti. Terima kasih
Puneet Verma
7

Saya akan mengatakan angular.copy(source);dalam situasi Anda tidak perlu jika nanti Anda tidak menggunakannya tanpa tujuan angular.copy(source, [destination]);.

Jika tujuan disediakan, semua elemennya (untuk array) atau propertinya (untuk objek) dihapus dan kemudian semua elemen / properti dari sumber disalin ke sana.

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

Esko
sumber
Terima kasih Esko! Mencoba meluruskan kepalaku. Apakah itu berarti keuntungan bagi angular.copy adalah: jika sebuah variabel sudah memiliki data yang terkait dengannya, ini adalah cara yang lebih bersih untuk menugaskan ulang elemen / properti?
Superman2971
1
Anda menggunakan angular.copy()objek untuk mencegah kode lain mengubahnya. Objek asli mungkin berubah, tetapi salinan Anda tidak akan melihat perubahan. Anda dapat memulihkan salinan tersebut jika perlu.
Esko
1

Saat menggunakan angular.copy, alih-alih memperbarui referensi, objek baru dibuat dan ditetapkan ke tujuan (jika tujuan disediakan). Tapi masih ada lagi. Ada hal keren yang terjadi setelah deep copy.

Katakanlah Anda memiliki layanan pabrik yang memiliki metode yang memperbarui variabel pabrik.

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

dan pengontrol yang menggunakan layanan ini,

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

Ketika program di atas dijalankan outputnya adalah sebagai berikut,

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

Jadi hal yang keren tentang menggunakan salinan sudut adalah, referensi tujuan direfleksikan dengan perubahan nilai, tanpa harus menetapkan ulang nilai secara manual, lagi.

Pubudu Dodangoda
sumber
1

Saya tahu ini sudah dijawab, tetap saja saya hanya mencoba membuatnya sederhana. Jadi angular.copy (data) dapat Anda gunakan jika Anda ingin memodifikasi / mengubah objek yang Anda terima dengan menjaga nilai aslinya tidak dimodifikasi / tidak berubah.

Sebagai contoh: misalkan saya telah membuat panggilan api dan mendapatkan originalObj saya, sekarang saya ingin mengubah nilai api originalObj untuk beberapa kasus tetapi saya ingin nilai aslinya juga jadi yang bisa saya lakukan adalah, saya bisa membuat salinan api originalObj saya di duplikatObj dan modifikasi duplikatObj dengan cara ini nilai originalObj saya tidak akan berubah. Dengan kata sederhana modifikasi duplikatObj tidak akan mencerminkan originalObj tidak seperti bagaimana js obj berperilaku.

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

Hasilnya seperti ....

    ----------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"}
Sudarshan Kalebere
sumber
1

Saya hanya berbagi pengalaman saya di sini, saya menggunakan angular.copy () untuk membandingkan dua properti objek. Saya sedang mengerjakan sejumlah input tanpa elemen formulir, saya bertanya-tanya bagaimana cara membandingkan dua properti objek dan berdasarkan hasil saya harus mengaktifkan dan menonaktifkan tombol simpan. Jadi saya gunakan seperti di bawah ini.

Saya menetapkan nilai pengguna objek server asli ke objek dummy saya untuk mengatakan userCopy dan menggunakan jam tangan untuk memeriksa perubahan pada objek pengguna.

API server saya yang mengambil saya data dari server:

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

Saya tidak yakin tetapi membandingkan dua objek itu benar-benar membuat saya pusing bagi saya selalu tetapi dengan angular.copy () itu berjalan lancar.

Sudarshan Kalebere
sumber
-2

Javascript meneruskan variabel by reference, ini berarti:

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

Sekarang karena by referencepartnya i[1], dan jis [1] juga, meski baru idiganti. Ini karena ketika kita mengatakan j = ijavascript tidak menyalin ivariabel dan menugaskannya jtetapi mereferensikan ivariabel j.

Salinan sudut membuat kita kehilangan referensi ini, yang artinya:

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

Sekarang di isini sama dengan [1], sementara jmasih sama dengan [].

Ada situasi ketika copyfungsionalitas semacam itu sangat berguna.

guramidev.dll
sumber
1
JavaScript meneruskan objek dengan referensi. Bukan primitif. Uji kode Anda.
Oleg
Yah, idenya kurang lebih sama, diedit
guramidev
1
Dan angular.copylebih cerdas dari serialisasi JSON karena dapat menangani fungsi.
Oleg
tidak tahu itu, saya bersumpah saya ingat melihat sumber sudut dan hanya melihat serialisasi JSON, tetapi saya memeriksanya lagi dan Anda benar.
guramidev