ค้นหาเว็บไซต์

angular - โคลนอาเรย์ใน Javascript/Typescript


ฉันมีอาเรย์ของวัตถุสองตัว:

genericItems: Item[] = [];
backupData: Item[] = [];

ฉันกำลังเติมข้อมูลในตาราง HTML ของฉันด้วยข้อมูล genericItems ตารางนี้สามารถแก้ไขได้ มีปุ่มรีเซ็ตเพื่อเลิกทำการเปลี่ยนแปลงทั้งหมดที่ทำด้วย backUpData อาร์เรย์นี้ถูกเติมโดยบริการ:

getGenericItems(selected: Item) {
this.itemService.getGenericItems(selected).subscribe(
  result => {
     this.genericItems = result;
  });
     this.backupData = this.genericItems.slice();
  }

ความคิดของฉันคือ การเปลี่ยนแปลงของผู้ใช้จะสะท้อนในอาร์เรย์แรก และอาร์เรย์ที่สองสามารถใช้เป็นสำรองสำหรับการรีเซ็ต ปัญหาที่ฉันพบที่นี่คือเมื่อผู้ใช้แก้ไขตาราง (genericItems[]) อาร์เรย์ที่สอง backupData ก็ถูกแก้ไขด้วยเช่นกัน

นี่เกิดขึ้นได้อย่างไรและจะป้องกันได้อย่างไร?

คำตอบ #1

โคลนวัตถุ:

const myClonedObject = Object.assign({}, myObject); 

โคลนอาเรย์:

  • ตัวเลือก 1 ถ้าคุณมีอาร์เรย์ของชนิดข้อมูลพื้นฐาน:
const myClonedArray  = Object.assign([], myArray);
  • ตัวเลือก 2 - ถ้าคุณมีอาร์เรย์ของวัตถุ:
const myArray= [{ a: 'a', b: 'b' }, { a: 'c', b: 'd' }];
const myClonedArray = [];
myArray.forEach(val => myClonedArray.push(Object.assign({}, val)));

คำตอบ #2

การโคลนอาร์เรย์และออบเจ็กต์ใน JavaScript มีไวยากรณ์ที่แตกต่างกัน เร็วหรือช้าทุกคนก็จะเรียนรู้ความแตกต่างในวิธีที่ยากและลงเอยที่นี่

ใน Typescript และ ES6 คุณสามารถใช้ตัวดำเนินการแพร่กระจายสำหรับอาร์เรย์และอ็อบเจ็กต์:

const myClonedArray  = [...myArray];  // This is ok for [1,2,'test','bla']
                                      // But wont work for [{a:1}, {b:2}]. 
                                      // A bug will occur when you 
                                      // modify the clone and you expect the 
                                      // original not to be modified.
                                      // The solution is to do a deep copy
                                      // when you are cloning an array of objects.

ในการทำสำเนาลึกของวัตถุ คุณต้องใช้ไลบรารีภายนอก:

import {cloneDeep} from 'lodash';
const myClonedArray = cloneDeep(myArray);     // This works for [{a:1}, {b:2}]

โอเปอเรเตอร์การกระจายทำงานกับอ็อบเจ็กต์ได้เช่นกัน แต่จะทำการคัดลอกแบบตื้นเท่านั้น (ชั้นแรกของลูก)

const myShallowClonedObject = {...myObject};   // Will do a shallow copy
                                               // and cause you an un expected bug.

ในการทำสำเนาลึกของวัตถุ คุณต้องใช้ไลบรารีภายนอก:

 import {cloneDeep} from 'lodash';
 const deeplyClonedObject = cloneDeep(myObject);   // This works for [{a:{b:2}}]

คำตอบ #3

การใช้ map หรือวิธีการคล้ายกันอื่น ๆ ไม่ช่วยในการคัดลอกแบบลึกของอาร์เรย์ของออบเจ็กต์ วิธีที่ง่ายกว่าที่จะทำสิ่งนี้โดยไม่ต้องเพิ่มไลบรารีใหม่คือการใช้ JSON.stringify แล้วตามด้วย JSON.parse

ในกรณีของคุณ สิ่งนี้ควรใช้ได้ :

this.backupData = JSON.parse(JSON.stringify(genericItems));
  • เมื่อใช้เวอร์ชันล่าสุดของ JS/TS การติดตั้งไลบรารีขนาดใหญ่เช่น lodash เพียงเพื่อฟังก์ชันหนึ่งหรือสองฟังก์ชันถือเป็นการตัดสินใจที่ไม่ดี คุณจะทำให้ประสิทธิภาพของแอปลดลง และในระยะยาวคุณจะต้องดูแลการอัปเกรดไลบรารี! ตรวจสอบได้ที่ https://bundlephobia.com/
  • สำหรับอ็อบเจ็กต์ขนาดเล็ก lodash cloneDeep อาจจะเร็วกว่า แต่สำหรับอ็อบเจ็กต์ที่ใหญ่ขึ้น/ซับซ้อนขึ้น json clone จะเร็วกว่ามาก ดังนั้นในกรณีเหล่านี้คุณไม่ควรลังเลที่จะใช้มัน ตรวจสอบได้ที่ https://www.measurethat.net/Benchmarks/Show/6039/0/lodash-clonedeep-vs-json-clone-larger-object และสำหรับข้อมูลเพิ่มเติม https://v8.dev/blog/cost-of-javascript-2019#json

  • ความไม่สะดวกคือวัตถุต้นทางของคุณต้องสามารถแปลงเป็น JSON ได้

คำตอบ #4

ลองใช้โค้ดต่อไปนี้:

this.cloneArray= [...this.OriginalArray]

บทความที่เกี่ยวข้อง