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)。uがajax呼び出しからオブジェクトを受け取った場合($ http、$ resourceなど)、コピーする必要はありません。ただし、このオブジェクトをビューで変更したいが、元のオブジェクトを何らかのキャッシュに保持したい場合は、コピーすることをお勧めします。
Petr Averyanov、2015年

回答:


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を作成する代わりに、情報を2つの別々の変数に保存し、それらのプロパティを個別に調整できますか?例:$scope.one = response.dataそしてset $scope.two = response.data。その後、行います$scope.two.addProperty = something。私はおそらくこれをテストするだけです:)が、コミュニティの洞察を得たいと思います。
Superman2971

2
回答:いいえ。理由:object property新しい参照の値を同じ参照を持つすべてのオブジェクトに変更します。そのため、angular.copyを使用する必要があります
Sarjan Desai

44

その場合、使用する必要はありません angular.copy()

説明

  • =参照を表しangular.copy()ますが、新しいオブジェクトをディープコピーとして作成します。

  • を使用=すると、のプロパティをresponse.data変更すると、の対応するプロパティが変更され、$scope.example逆も同様です。

  • angular.copy()2つのオブジェクトを使用しても分離したままであり、変更は互いに反映されません。


最も簡単な答え。
Astitva Srivastava

理解しやすいです。ありがとう
Puneet Verma

7

私はangular.copy(source);あなたがあなたの状況で不必要であると言うならば、あなたが後であなたが使わないならば、それは目的地なしでそれであるangular.copy(source, [destination]);

宛先が指定されている場合、そのすべての要素(配列の場合)またはプロパティ(オブジェクトの場合)が削除され、ソースのすべての要素/プロパティがそこにコピーされます。

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


Esko、ありがとう!私の頭をまっすぐにしようとしています。これは、angular.copyの利点が意味することを意味します:変数に既にデータが関連付けられている場合、これは要素/プロパティを再割り当てするためのよりクリーンな方法ですか?
Superman2971

1
angular.copy()オブジェクトを使用して、他のコードがオブジェクトを変更できないようにします。元のオブジェクトは変更される可能性がありますが、コピーには変更が反映されません。必要に応じて、コピーを復元できます。
Esko

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(data)を使用すると、元の値を未変更/未変更のままにして、受信したオブジェクトを変更/変更したい場合に使用できます。

例: api呼び出しを行い、originalObjを取得したとしましょう。今度はapi originalObjの値を変更したいのですが、元の値も欲しいので、api originalObjのコピーを作成できます。 duplicateObjでduplicateObjを変更して、このようにoriginalObj値が変更されないようにします。簡単に言うと、jsobjの動作とは異なり、replicateObjの変更はoriginalObjに反映されません。

 $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

私はここで私の経験を共有しています。2つのオブジェクトのプロパティを比較するためにangular.copy()を使用しました。私はフォーム要素のない多数の入力に取り組んでおり、2つのオブジェクトのプロパティを比較する方法を知り、結果に基づいて保存ボタンを有効または無効にする必要がありました。以下のように使用しました。

元のサーバーオブジェクトのユーザー値をダミーオブジェクトに割り当ててuserCopyとし、監視を使用してユーザーオブジェクトへの変更を確認しました。

サーバーからデータを取得するサーバー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);

よくわかりませんが、2つのオブジェクトを比較することは常に私にとって頭痛の種でしたが、angular.copy()を使用するとスムーズに進みました。


-2

JavaScriptは変数を渡しますby reference。つまり、次のことを意味します。

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

変更されただけなのに、by referenceパーツiが[1]であるため、j[1]も同様iです。これは、j = ijavascriptがi変数をコピーして割り当てないがjiを介して変数を参照するためjです。

Angularコピーを使用すると、この参照が失われます。つまり、

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

ここiで[1]と等しくなりますが、jまだ[]と等しくなります。

このようなcopy機能が非常に便利な場合があります。


1
JavaScriptは参照によってオブジェクトを渡します。プリミティブではありません。コードをテストします。
Oleg

ええ、アイデアはかなり同じですが、編集されました
guramidev '10

1
そしてangular.copy、それは機能を扱うことができるので、JSONのシリアライズそれよりインテリジェントです。
Oleg

それを知らなかったので、角度のあるソースを見て、JSONのシリアル化のみを確認することを覚えていると誓ったかもしれませんが、もう一度チェックしてみました。
guramidev 2015年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.