언제 그리고 언제 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
객체 (: D)의 사본이 필요한 경우 angular.copy를 사용해야합니다. Ajax 호출 ($ http, $ resource, ...)에서 객체를 수신하면 복사 할 필요가 없습니다. 그러나이 객체를보기에서 수정하지만 원본 객체를 일종의 캐시에 유지하려는 경우 복사를 원할 수 있습니다.
Petr Averyanov

답변:


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를 만드는 대신 정보를 두 개의 개별 변수에 저장하고 속성을 개별적으로 조정할 수 있습니까? 예 : $scope.one = response.data및 설정 $scope.two = response.data. 그런 다음 $scope.two.addProperty = something. 아마 이것을 테스트해야합니다 :)하지만 커뮤니티 통찰력을 얻고 싶습니다.
Superman2971

2
An : No. 이유 : object property동일한 참조를 갖는 모든 객체로 새 값 업데이트 값을 변경합니다 . 그래서 angular.copy를 사용해야합니다.
Sarjan Desai

44

이 경우에는 사용할 필요가 없습니다 angular.copy()

설명 :

  • =는 참조를 나타내지 만 angular.copy()새 개체를 깊은 복사본으로 만듭니다.

  • 를 사용하면 =속성을 response.data변경하면 해당 속성이 변경 $scope.example되거나 그 반대로 변경됩니다.

  • angular.copy()두 개체를 사용 하면 별도로 유지되며 변경 사항은 서로 반영되지 않습니다.


가장 간단한 답변.
Astitva Srivastava

이해하기 쉽다. 감사합니다
Puneet 베르

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의 사본을 만들 수 있습니다. 이 방법으로 duplicateObj에서 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

나는 여기서 내 경험을 공유하고 있는데 두 개의 객체 속성을 비교하기 위해 angular.copy ()를 사용했습니다. 양식 요소가없는 여러 입력 작업을하고 있었으며 두 객체 속성을 비교하는 방법이 궁금하고 결과를 기반으로 저장 버튼을 활성화 및 비활성화해야합니다. 그래서 나는 아래와 같이 사용했다.

사용자 서버를 말하도록 원래 서버 오브젝트 사용자 값을 더미 오브젝트에 지정하고 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();
});

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

확실하지는 않지만 두 객체를 비교하면 항상 두통 이었지만 angular.copy ()를 사용하면 원활하게 진행됩니다.


-2

Javascript는 variables를 전달합니다 by reference. 이는 다음을 의미합니다.

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

하기 때문에 by reference부분 i[1]이며, j[1]뿐만 아니라, 비록 아니라 i변경 하였다. 이것은 j = i자바 스크립트가 i변수를 복사하지 않고 변수를 할당 j하지만 i변수를 참조 한다고 말할 때입니다.j 입니다.

각도 복사를 사용하면이 참조를 잃을 수 있습니다.

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

이제 i여기는 [1]과 같습니다.j 여전히 []와 같습니다.

이러한 종류의 copy기능이 매우 편리한 상황이 있습니다 .


1
자바 스크립트는 객체 를 참조로 전달 합니다 . 프리미티브가 아닙니다. 코드를 테스트하십시오.
Oleg

그래, 그 아이디어는 거의 동일하지만 편집되었다
guramidev

1
그리고 angular.copy함수를 처리 할 수 ​​있기 때문에 JSON 직렬화보다 지능적입니다.
Oleg

몰랐다, 나는 각도 소스를보고 JSON 직렬화 만 보았던 것을 기억할 수 있다고 맹세했지만 다시 확인하고 당신이 옳았다.
guramidev
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.