Sao chép / sao chép một phiên bản Bản đồ


88

Làm cách nào để sao chép / sao chép bản đồ trong JavaScript?

Tôi biết cách sao chép một mảng nhưng làm cách nào để sao chép / sao chép bản đồ?

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

2
ES6 cho phép bạnlet copy = {...myMap};
Reactgular

Câu trả lời:


16

Một cách đơn giản (để sao chép nông) là sao chép từng thuộc tính của bản đồ nguồn vào bản đồ đích:

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

LƯU Ý: newMap [i] rất có thể là một tham chiếu đến cùng một đối tượng như myMap [i]


6
đây chỉ là một bản sao cạn ... điều gì sẽ xảy ra nếu myMap [i] là một bản đồ?
Stefano

1
Stefano, bạn có thể làm điều đó nếu bạn muốn (kiểm tra xem liệu có phải là một đối tượng có typeof hay không, sau đó thực hiện sao chép các thuộc tính của nó ... có thể bằng cách đệ quy cùng một hàm), nhưng hãy nhớ rằng bây giờ bạn phải quan tâm đến khả năng chúng là một phần tử tổ tiên trong đó sẽ đưa bạn vào một vòng lặp vô hạn. Nếu bạn thực sự muốn có một bản sao sâu, bạn có thể muốn xem xét các thư viện để làm điều đó.
cướp

4
Tôi biết, nhưng tôi nghĩ bạn nên viết bài này trong câu trả lời của bạn ở nơi đầu tiên ;-)
Stefano

5
Đây không phải là Bản đồ mà là một Đối tượng. Chênh lệch nhỏ và cho thuê lại. cf. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
helt

1
Nó sẽ không sao chép mỗi thuộc tính bạn wont có quyền truy cập vào setters và thu khí như chỉ của nó một đối tượng
Amante Ninja

331

Với sự ra đời của Maps trong JavaScript, nó khá đơn giản khi xem xét hàm tạo chấp nhận một tệp có thể lặp lại:

var newMap = new Map(existingMap)

Tài liệu tại đây: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map


4
Một lưu ý nhỏ ở trên: Sao chép một bản đồ như thế này, sẽ gọi Map.prototype.entriesMap.prototype.set. Điều đó có nghĩa là: Nếu bạn viết một lớp mở rộng Bản đồ ghi đè một trong hai phương thức này, thì việc viết đơn giản new ExtendedMap( extendedMapObj )sẽ không hoạt động nếu các phương thức mở rộng dựa vào các thuộc tính không có sẵn cho siêu.

nó nhân bản sâu hay chỉ nhân bản nông? Giả sử tôi đã lồng đối tượng dưới dạng các giá trị
Madeo

nhưng nó làm một bản sao sâu hay nông ??
Yonatan Nir

5
Điều này sẽ làm một bản sao cạn, không sâu: jsfiddle.net/jormwe69
Jaap

1
@PeterCoester Cần chúng ta nói rằng các tiệm cận của var newMap = new Map(existingMap)O(n)nơi nlà số các cặp khóa / giá trị của bản đồ? Tôi đoán rằng hoạt động nhân bản không liên tục O(1)nếu, như bạn nói, Map.prototype.entries được gọi là ẩn ...
tonix

11

Rất đơn giản để sao chép bản đồ vì những gì bạn đang nói chỉ là một đối tượng. Có một Maptrong ES6 mà bạn nên tra cứu, nhưng để sao chép một đối tượng, chỉ cần sử dụngObject.assign()

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

Bạn cũng có thể sử dụng cloneDeep()từ Lodash

let copy = cloneDeep(map);

6

JQuery có một phương thức để mở rộng một đối tượng (hợp nhất hai đối tượng), nhưng phương thức này cũng có thể được sử dụng để sao chép một đối tượng bằng cách cung cấp một đối tượng trống.

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

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

Bạn có thể tìm thêm thông tin trong tài liệu jQuery .


3

Không có gì được xây dựng trong.

Sử dụng máy photocopy thuộc tính đệ quy đã được kiểm tra tốt hoặc nếu hiệu suất không phải là vấn đề, hãy tuần tự hóa thành JSON và phân tích cú pháp lại thành một đối tượng mới.


2

Không có bản sao / bản sao cài sẵn. Bạn có thể viết phương pháp của riêng mình vào bản sao nông hoặc sâu:

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;
}

Tất cả các đối tượng trong Javascript là động và có thể được gán các thuộc tính mới. Một "bản đồ" như bạn đề cập đến nó thực sự chỉ là một đối tượng rỗng. Mảng cũng là một đối tượng, với các phương thức như slicevà các thuộc tính như length.


Không hiểu 2 hàm bạn viết có gì khác nhau!
Hasan A Yousef

@HasanAYousef Sự khác biệt không được thực hiện; Trong bản sao sâu, bạn phải đệ quy (gọi deepCopy cho mỗi con), nhưng vì con có thể chứa tham chiếu đến cha (ví dụ window.window2 = window), bạn không thể sao chép sâu các tham chiếu đó mà không vướng vào vòng lặp vô tận.
Nicole

2

Nếu bạn cần tạo một bản sao sâu của Bản đồ, bạn có thể sử dụng các cách sau:

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

Trong trường hợp sourcelà đối tượng Bản đồ gốc.

Lưu ý rằng điều này có thể không phù hợp cho tất cả các trường hợp sử dụng mà các giá trị Bản đồ không thể tuần tự hóa, để biết thêm chi tiết, hãy xem: https://stackoverflow.com/a/122704/10583071


Tôi đã chạy thử nghiệm trên jsperf và nhận thấy rằng cách tiếp cận lặp lại nhanh hơn 10 lần: jsperf.com/deep-copy-map
Zack Burt

2
@ZackBurt Đáng buồn thay, giải pháp thay thế được đề xuất nhanh hơn của bạn không thực sự tạo ra deep copymục tiêu Mapmà nó chỉ là shallow copy. Có lẽ đây là lý do tại sao nó quá nhanh?
Alfonso M. García Astorga

@ AlfonsoM.GarcíaAstorga Cảm ơn bạn đã làm rõ (đã ủng hộ). Bạn đúng ở chỗ nó không phải là một bản sao sâu. Nhưng nó là một bản sao nhanh hơn với <10kb dữ liệu. Bài đọc bổ sung được đề xuất: v8.dev/blog/cost-of-javascript-2019#json
Zack Burt vào

1

Tôi nhận thấy rằng Bản đồ cần được xử lý đặc biệt, do đó với tất cả các đề xuất trong chuỗi này, mã sẽ là:

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;
}

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.