ทำไมและเมื่อใช้ angular.copy (สำเนาลึก)


136

ฉันบันทึกข้อมูลทั้งหมดที่ได้รับจากบริการโดยตรงไปยังตัวแปรท้องถิ่นตัวควบคุมหรือขอบเขต สิ่งที่ฉันคิดว่าจะถือว่าเป็นสำเนาตื้น ๆ ถูกต้องหรือไม่

Example:

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

เมื่อเร็ว ๆ นี้ฉันได้รับคำสั่งให้ใช้ angular.copy เพื่อสร้างสำเนาลึก

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

อย่างไรก็ตามข้อมูลสำเนาลึกดูเหมือนว่าจะทำงานในลักษณะเดียวกันเมื่อใช้งานโดยแอปพลิเคชันเชิงมุมของฉัน มีประโยชน์ที่เฉพาะเจาะจงในการใช้สำเนาลึก (angular.copy) และคุณช่วยอธิบายพวกเขาให้ฉันได้ไหม


2
คุณต้องใช้ angular.copy หากคุณต้องการสำเนาของวัตถุ (: D) หากคุณได้รับวัตถุจากการโทร 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 จะเป็นการคัดลอกตัวอักษร ความหมายฉันควรใช้เฉพาะเมื่อต้องการสำเนาที่เป็นต้นฉบับซึ่งฉันสามารถเปลี่ยนคุณสมบัติได้ ฉันสามารถบันทึกข้อมูลให้กับตัวแปรสองตัวที่แยกกันและปรับคุณสมบัติของพวกมันแยกจากกันหลังจากทำการสร้างเชิงมุมได้หรือไม่ ตัวอย่าง: ชุด$scope.one = response.data แล้วทำ$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()วัตถุทั้งสองจะยังคงแยกจากกันและการเปลี่ยนแปลงจะไม่สะท้อนซึ่งกันและกัน


คำตอบที่ง่ายที่สุด
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 ของฉัน ใน DupObj และแก้ไข DupObj ด้วยวิธีนี้ค่า originalObj ของฉันจะไม่เปลี่ยนแปลง ในคำง่าย ๆ การแก้ไขซ้ำซ้อน Obj จะไม่สะท้อนใน originalObj ซึ่งแตกต่างจากวิธีการ 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);

ผลลัพธ์เป็นเช่น ....

    ----------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 () เพื่อเปรียบเทียบคุณสมบัติของวัตถุสองอย่าง ฉันกำลังทำงานกับอินพุตจำนวนหนึ่งที่ไม่มีองค์ประกอบของฟอร์มฉันสงสัยว่าจะเปรียบเทียบคุณสมบัติของวัตถุสองอย่างอย่างไรและจากผลลัพธ์ที่ฉันต้องเปิดใช้งานและปิดใช้งานปุ่มบันทึก ดังนั้นฉันใช้เป็นด้านล่าง

ฉันกำหนดค่าผู้ใช้วัตถุเซิร์ฟเวอร์ดั้งเดิมให้กับวัตถุจำลองของฉันเพื่อบอกว่า 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();
});

//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 ส่งผ่านตัวแปรby referenceซึ่งหมายความว่า:

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

ตอนนี้เพราะby referenceส่วนหนึ่งiคือ [1] และj[1] เช่นกันถึงแม้ว่าจะiเปลี่ยนไปเพียงเท่านั้น นี้เป็นเพราะเมื่อเราพูดj = iจาวาสคริปต์ไม่ได้คัดลอกiตัวแปรและกำหนดให้jแต่อ้างอิงผ่านตัวแปรij

สำเนาเชิงมุมทำให้เราสูญเสียการอ้างอิงนี้ซึ่งหมายความว่า:

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

ตอนนี้iที่นี่เท่ากับ [1] ในขณะที่jยังคงเท่ากับ []

มีบางสถานการณ์ที่copyฟังก์ชั่นการใช้งานประเภทนี้มีประโยชน์มาก


1
JavaScript ส่งผ่านวัตถุโดยอ้างอิง ไม่ใช่แบบดั้งเดิม ทดสอบรหัสของคุณ
Oleg

ใช่ความคิดนั้นค่อนข้างเหมือนเดิม แต่แก้ไขแล้ว
guramidev

1
และangular.copyฉลาดกว่านั้นคือ JSON ทำให้เป็นอันดับเพราะมันสามารถจัดการกับฟังก์ชั่น
Oleg

ไม่ทราบว่าฉันสามารถสาบานได้ฉันจำได้ว่ากำลังดูแหล่งเชิงมุมและเห็นการทำให้เป็นอันดับ JSON เท่านั้น แต่ฉันตรวจสอบอีกครั้งและคุณพูดถูก
guramidev
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.