ฉันจะคัดลอกแผนที่ลงในแผนที่ซ้ำได้อย่างไร [ซ้ำ]


96

ฉันจะโคลน / คัดลอกแผนที่ใน JavaScript ได้อย่างไร

ฉันรู้วิธีโคลนอาร์เรย์ แต่ฉันจะโคลน / คัดลอกแผนที่ได้อย่างไร

var myArray = new Array(1, 2, 3);
var copy    = myArray.slice();
// now I can change myArray[0] = 5; & it wont affect copy array

// Can I just do the same for map?
var myMap = new ?? // in javascript is it called a map?
var myMap = {"1": 1, "2", 2};
var copy  = myMap.slice(); 

3
ES6 ให้คุณlet copy = {...myMap};
Reactgular

คำตอบ:


15

วิธีง่ายๆ (ในการทำสำเนาตื้น) คือคัดลอกคุณสมบัติแต่ละรายการของแผนที่ต้นทางไปยังแผนที่เป้าหมาย:

var newMap = {};
for (var i in myMap)
   newMap[i] = myMap[i];

หมายเหตุ: newMap [i] สามารถอ้างอิงถึงวัตถุเดียวกันกับ myMap [i] ได้เป็นอย่างดี


6
นี่เป็นเพียงสำเนาตื้น ๆ เท่านั้น ... ถ้า myMap [i] เป็นแผนที่เองล่ะ?
Stefano

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

4
ฉันรู้ แต่ฉันคิดว่าคุณควรเขียนสิ่งนี้ไว้ในคำตอบของคุณตั้งแต่แรก ;-)
Stefano

6
นี่ไม่ใช่แผนที่ แต่เป็นวัตถุ ความแตกต่างเล็กน้อยและการเช่าช่วง cf. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
helt

1
มันจะไม่คัดลอกคุณสมบัติแต่ละอย่างที่คุณไม่สามารถเข้าถึง setters และ getters เป็นเพียงวัตถุ
Amante Ninja

352

ด้วยการแนะนำแผนที่ใน JavaScript มันค่อนข้างง่ายเมื่อพิจารณาว่าตัวสร้างยอมรับการทำซ้ำ:

var newMap = new Map(existingMap)

เอกสารที่นี่: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map


4
คำเตือนเล็ก ๆ ข้างต้น: โคลนแผนที่เช่นนี้จะเรียกและMap.prototype.entries Map.prototype.setนั่นหมายความว่า: หากคุณเขียนคลาสที่ขยายแผนที่และเขียนทับอย่างใดอย่างหนึ่งในสองวิธีนี้การเขียนเพียงอย่างเดียวnew ExtendedMap( extendedMapObj )จะไม่ได้ผลหากเมธอดขยายขึ้นอยู่กับคุณสมบัติที่ super ไม่สามารถใช้ได้

มันโคลนลึกหรือแค่โคลนตื้น? สมมติว่าฉันซ้อนวัตถุเป็นค่า
Madeo

แต่มันทำสำเนาลึกหรือตื้น ??
Yonatan Nir

5
สิ่งนี้จะทำสำเนาตื้นไม่ลึก: jsfiddle.net/jormwe69
Jaap

1
@PeterCoester ที่เราสามารถพูดได้ว่า asymptotic ของvar newMap = new Map(existingMap)เป็นO(n)ที่nคือจำนวนของคู่คีย์ / ค่าของแผนที่? ฉันเดาว่าการดำเนินการโคลนนิ่งไม่คงที่O(1)ถ้าอย่างที่คุณพูด Map.prototype.entries เรียกว่าภายใต้ประทุน ...
tonix

10

ง่ายมากในการโคลนแผนที่เนื่องจากสิ่งที่คุณกำลังพูดถึงเป็นเพียงวัตถุ มีMapES6 ใน ES6 ที่คุณควรค้นหา แต่หากต้องการคัดลอกวัตถุให้ใช้ไฟล์Object.assign()

let map = {"a": 1, "b": 2}
let copy = Object.assign({}, map);

คุณยังสามารถใช้cloneDeep()จาก Lodash

let copy = cloneDeep(map);

Object.assignคำเตือนสำหรับ Deep Clone: ​​"หากค่าต้นทางเป็นการอ้างอิงถึงอ็อบเจ็กต์ค่านั้นจะคัดลอกเฉพาะค่าอ้างอิงเท่านั้น"
Tom Hale

6

JQuery มีวิธีการขยายวัตถุ (การรวมวัตถุสองชิ้น) แต่วิธีนี้ยังสามารถใช้ในการโคลนวัตถุโดยการจัดเตรียมวัตถุว่าง

// Shallow copy
var newObject = jQuery.extend({}, oldObject);

// Deep copy
var newObject = jQuery.extend(true, {}, oldObject);

ข้อมูลเพิ่มเติมสามารถพบได้ในเอกสาร jQuery


3

ในตัวก็ไม่มีอะไร

ใช้เครื่องถ่ายเอกสารคุณสมบัติการเรียกซ้ำที่ผ่านการทดสอบมาเป็นอย่างดีหรือหากประสิทธิภาพไม่เป็นปัญหาให้ต่ออนุกรมกับ JSON และแยกวิเคราะห์อีกครั้งไปยังออบเจ็กต์ใหม่


2

ไม่มีโคลน / สำเนาในตัว คุณสามารถเขียนวิธีการของคุณเองได้ทั้งแบบตื้นหรือแบบลึก:

function shallowCopy(obj) {
    var result = {};
    for (var i in obj) {
        result[i] = obj[i];
    }
    return result;
}

function deepCopy(obj) {
    var result = {};
    for (var i in obj) {
        // recursion here, though you'll need some non-trivial logic
        // to avoid getting into an endless loop.
    }
    return result;
}

วัตถุทั้งหมดใน Javascript เป็นแบบไดนามิกและสามารถกำหนดคุณสมบัติใหม่ได้ "แผนที่" ตามที่คุณอ้างถึงนั้นแท้จริงแล้วเป็นเพียงวัตถุว่างเปล่า อาร์เรย์เป็นยังวัตถุที่มีวิธีการเช่นและคุณสมบัติเช่นslicelength


ไม่เข้าใจว่าความแตกต่างระหว่าง 2 ฟังก์ชั่นที่คุณเขียนคืออะไร!
Hasan A Yousef

@HasanAYousef ไม่ได้ใช้ความแตกต่าง; ในสำเนาลึกคุณต้องเรียกซ้ำ (เรียก deepCopy สำหรับเด็กแต่ละคน) แต่เนื่องจากเด็ก ๆ อาจมีการอ้างอิงถึงพาเรนต์ (เช่น window.window2 = window) คุณจึงไม่สามารถคัดลอกการอ้างอิงเหล่านั้นในระดับลึกได้โดยไม่ต้องวนซ้ำไม่รู้จบ
Nicole

2

หากคุณต้องการทำสำเนาแผนที่แบบละเอียดคุณสามารถใช้สิ่งต่อไปนี้:

new Map(JSON.parse(JSON.stringify(Array.from(source))));

sourceวัตถุแผนที่ดั้งเดิมอยู่ที่ไหน

โปรดทราบว่าสิ่งนี้อาจไม่เหมาะสำหรับทุกกรณีการใช้งานที่ค่าแผนที่ไม่สามารถต่อเนื่องได้สำหรับรายละเอียดเพิ่มเติมโปรดดู: https://stackoverflow.com/a/122704/10583071


ฉันทำการทดสอบ jsperf และพบว่าวิธีการวนซ้ำเร็วขึ้น 10 เท่า: jsperf.com/deep-copy-map
Zack Burt

3
@ZackBurt เศร้าเสนอทางเลือกของคุณได้เร็วขึ้นไม่สร้างจริงๆdeep copyของเป้าหมายจะเป็นเพียงMap shallow copyอาจเป็นเพราะเหตุนี้จึงเร็วมาก?
Alfonso M. García Astorga

@ AlfonsoM.GarcíaAstorgaขอบคุณสำหรับการชี้แจง (โหวตขึ้นตามลำดับ) คุณเข้าใจถูกแล้วว่าไม่ใช่สำเนาลึก แต่เป็นสำเนาที่เร็วกว่าโดยมีข้อมูล <10kb การอ่านเพิ่มเติมที่แนะนำ: v8.dev/blog/cost-of-javascript-2019#json
Zack Burt

1

ฉันสังเกตเห็นว่าแผนที่ควรต้องได้รับการดูแลเป็นพิเศษดังนั้นด้วยคำแนะนำทั้งหมดในชุดข้อความนี้รหัสจะเป็น:

function deepClone( obj ) {
    if( !obj || true == obj ) //this also handles boolean as true and false
        return obj;
    var objType = typeof( obj );
    if( "number" == objType || "string" == objType ) // add your immutables here
        return obj;
    var result = Array.isArray( obj ) ? [] : !obj.constructor ? {} : new obj.constructor();
    if( obj instanceof Map )
        for( var key of obj.keys() )
            result.set( key, deepClone( obj.get( key ) ) );
    for( var key in obj )
        if( obj.hasOwnProperty( key ) )
            result[key] = deepClone( obj[ key ] );
    return result;
}

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