web-dev-qa-db-ja.com

Angular.copyを使用する理由とその理由(ディープコピー)

サービスから受け取ったすべてのデータをローカル変数、コントローラ、またはスコープに直接保存しています。浅いコピーと見なされると思いますが、それは正しいですか?

Example:

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

最近、ディープコピーを作成するためにangular.copyを使うように言われました。

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

ただし、ディープコピー情報は、私のAngularアプリケーションで使用されるときと同じように機能しているようです。 ディープコピー(angular.copy)を使用することには特定の利点がありますか?それらを私に説明してください。

123
Superman2971

object/arrayの値を別の変数に代入するときに angular.copy を使用し、そのobjectの値を変更しないでください。

deep copyangular.copyを使用しないで、propertyの値を変更したり、新しいプロパティを追加したり同じオブジェクトを参照するすべてのobjectを更新する.

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>
156
Sarjan Desai

その場合、angular.copy()を使う必要はありません。

説明

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

  • =を使用すると、response.dataのプロパティを変更すると、それに対応する$scope.exampleのプロパティも変更されます。

  • angular.copy()を使用すると、2つのオブジェクトは別々のままになり、変更はお互いに反映されません。

41
Nicolas2bert

あなたが後で使用しないのであれば目的地angular.copy(source);がなければangular.copy(source, [destination]);は不要です。

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

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

7
Esko

私はここで自分の経験を共有しているだけで、2つのオブジェクトのプロパティを比較するためにangular.copy()を使いました。私はフォーム要素なしでいくつかの入力に取り組んでいました、私は2つのオブジェクトのプロパティを比較する方法を考えていました、そして結果に基づいて保存ボタンを有効または無効にしなければなりません。だから私は以下のように使用しました。

オリジナルのサーバーオブジェクトuser値を私のダミーオブジェクトと言うuserCopyに割り当て、watchを使ってユーザーオブジェクトへの変更をチェックしました。

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

//最初はオブジェクトが同じであるため、保存ボタンが無効になっています。

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

よくわかりませんが、2つのオブジェクトを比較するのはいつも頭の痛い問題でしたが、angle.copy()を使用するとうまくいかなかったのです。

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の値を変更したいのですが、元の値も変更したいので、コピーすることができます。 duplicateObj内の私のapi originalObjの値を変更し、この方法でduplicateObjを変更すると、originalObjの値は変更されません。簡単に言うと、duplicateObjの変更は、js objの動作と異なり、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