Làm thế nào để bạn sao chép một mảng các đối tượng trong Javascript?


421

... Trong đó mỗi đối tượng cũng có tham chiếu đến các đối tượng khác trong cùng một mảng?

Khi tôi lần đầu tiên gặp vấn đề này, tôi chỉ nghĩ như vậy

var clonedNodesArray = nodesArray.clone()

sẽ tồn tại và tìm kiếm thông tin về cách sao chép các đối tượng trong javascript. Tôi đã tìm thấy một câu hỏi trên StackOverflow (được trả lời bởi chính @JohnResig) và anh ấy đã chỉ ra rằng với jQuery bạn có thể làm

var clonedNodesArray = jQuery.extend({}, nodesArray);

để nhân bản một đối tượng. Tôi đã thử điều này mặc dù, điều này chỉ sao chép các tham chiếu của các đối tượng trong mảng. Vì vậy, nếu tôi

nodesArray[0].value = "red"
clonedNodesArray[0].value = "green"

giá trị của cả hai nútArray [0] và cloneNodesArray [0] sẽ trở thành "màu xanh lá cây". Sau đó tôi đã thử

var clonedNodesArray = jQuery.extend(true, {}, nodesArray);

trong đó sao chép sâu một đối tượng, nhưng tôi nhận được thông báo " quá nhiều đệ quy " và " tràn ngăn xếp kiểm soát " từ cả Firefly và Opera Dragonfly.

Bạn sẽ làm điều này như thế nào? Đây có phải là một cái gì đó thậm chí không nên được thực hiện? Có cách nào để sử dụng lại trong Javascript không?

Câu trả lời:


106

Vấn đề với bản sao nông của bạn là tất cả các đối tượng không được nhân bản. Mặc dù các tham chiếu đến từng đối tượng là duy nhất trong mỗi mảng, nhưng cuối cùng khi bạn nắm bắt được nó, bạn sẽ xử lý cùng một đối tượng như trước. Không có gì sai với cách bạn nhân bản nó ... kết quả tương tự sẽ xảy ra khi sử dụng Array.slice ().

Lý do bản sao sâu của bạn gặp vấn đề là vì bạn kết thúc với các tham chiếu đối tượng hình tròn. Sâu sẽ đi sâu hết mức có thể và nếu bạn có một vòng tròn, nó sẽ tiếp tục vô tận cho đến khi trình duyệt bị ngất.

Nếu cấu trúc dữ liệu không thể được biểu diễn dưới dạng biểu đồ chu kỳ có hướng, thì tôi không chắc bạn sẽ có thể tìm thấy một phương pháp đa mục đích để nhân bản sâu. Biểu đồ tuần hoàn cung cấp nhiều trường hợp góc khó, và vì đó không phải là một thao tác phổ biến, tôi nghi ngờ bất kỳ ai cũng đã viết một giải pháp đầy đủ (nếu có thể - có thể không! Nhưng tôi không có thời gian để thử viết một bằng chứng nghiêm ngặt bây giờ.). Tôi tìm thấy một số ý kiến ​​tốt về vấn đề trên trang này .

Nếu bạn cần một bản sao sâu của Mảng đối tượng với các tham chiếu vòng tròn, tôi tin rằng bạn sẽ phải mã hóa phương thức của riêng mình để xử lý cấu trúc dữ liệu chuyên ngành của mình, sao cho nó là một bản sao nhiều lần:

  1. Trên vòng một, tạo một bản sao của tất cả các đối tượng không tham chiếu các đối tượng khác trong mảng. Theo dõi nguồn gốc của từng đối tượng.
  2. Trên vòng hai, liên kết các đối tượng với nhau.

1
Cố định liên kết cho @PatrickdeKleijn câu trả lời: web.archive.org/web/20140222022056/http://my.opera.com/...
Mike Szyndel

531

Miễn là các đối tượng của bạn chứa nội dung tuần tự hóa JSON (không có hàm, không Number.POSITIVE_INFINITY, v.v.), không cần bất kỳ vòng lặp nào để sao chép mảng hoặc đối tượng. Đây là một giải pháp vanilla tinh khiết một dòng.

var clonedArray = JSON.parse(JSON.stringify(nodesArray))

Để tóm tắt các ý kiến ​​dưới đây, ưu điểm chính của phương pháp này là nó cũng nhân bản nội dung của mảng, không chỉ bản thân mảng. Nhược điểm chính là giới hạn của nó chỉ hoạt động trên nội dung tuần tự hóa JSON và hiệu suất của nó (kém hơn đáng kể so với slicecách tiếp cận dựa trên).


118
Điều này có thể hoạt động đối với dữ liệu JSON, nhưng nếu mảng của bạn chứa bất kỳ hàm hoặc thể hiện nào của các đối tượng có phương thức, hãy nói lời tạm biệt với chúng.
sp0rkyd0rky

12
hãy cẩn thận nếu bạn có một mảng chứa giá trị Infinity. Giá trị này bị mất (là null sau đó). ( jsfiddle.net/klickagent/ehm4bd3s )
klickagent.ch

13
Đây chỉ là một cách tiếp cận tồi trừ khi mảng của bạn chỉ chứa các nguyên hàm và / hoặc các đối tượng mà chúng chỉ chứa các nguyên hàm chuỗi / số / boolean (thậm chí nullundefinedsẽ có vấn đề, vì JSON không hỗ trợ chúng). Hơn nữa, đó là một hoạt động kém hiệu quả hơn nhiều old_array.slice(0);, hoạt động tốt hơn và nhanh hơn.
XML

2
nếu đối tượng của mảng có DateTime, thì chuỗi sẽ được trả về thay vì DateTime! Ngày mới! == JSON.parse (JSON.opesify (Ngày mới))
MarkosyanArtur

2
Dòng chính trong câu hỏi của OP, câu trả lời này ở trên bỏ qua hoàn toàn: ... trong đó mỗi đối tượng cũng có tham chiếu đến các đối tượng khác trong cùng một mảng?
XML

288

Tôi đã giải quyết nhân bản một mảng các đối tượng với Object.assign

const newArray = myArray.map(a => Object.assign({}, a));

hoặc thậm chí ngắn hơn với cú pháp lây lan

const newArray = myArray.map(a => ({...a}));

15
Nhưng nếu myArray chứa một loạt Khủng long, newArray chứa một loạt các Đối tượng. Điều đó thật khập khiễng, bạn có đồng ý không?
Matthew James Davis

3
Cách tiếp cận tốt nhất, vì nó giữ cho các đối tượng hoạt động, sau đó mất chúng với JSON.parse (JSON.opesify (odesArray))
scipper

14
@MatthewJamesDavis bạn có thể giải quyết điều này bằng cách thay thế {}bằng new Dinosaur().
Agargara

5
bản sao nông không sao chép sâu
sultan aslam

1
Điều này hoạt động rất tốt cho một loạt các đối tượng, nếu những đối tượng đó chỉ chứa các thuộc tính nguyên thủy ... đó là những gì tôi cần, cảm ơn
mojave

154

Nếu tất cả những gì bạn cần là một bản sao nông, một cách thực sự dễ dàng là:

new_array = old_array.slice(0);

6
Tôi không nghĩ rằng bạn phải vượt qua 0, dù sao bạn cũng có thể gọi .slice()ít nhất bằng chrome
slf

112
Điều này không thực sự làm việc mặc dù, phải không? Ý tôi là, đó không phải là một câu trả lời cho câu hỏi làm thế nào để sao chép một mảng các đối tượng. Đây là giải pháp để sao chép một mảng đơn giản.
bozdoz

35
Trên thực tế điều này sẽ không làm việc cho một mảng đối tượng. Mảng được trả về bởi slicesẽ là một mảng mới nhưng sẽ chứa các tham chiếu đến các đối tượng mảng ban đầu.
Sergio A.

4
Điều này sẽ chỉ hoạt động cho "generic" int, chuỗi, vv nhưng không cho một mảng các đối tượng.
Stefan Michev

5
đối với mảng các đối tượng không thực sự sao chép, cập nhật lên new_array cũng sẽ cập nhật old_array.
Anas

44

Cách tốt nhất và cập nhật nhất để thực hiện bản sao này như sau:

Sử dụng ...toán tử trải ES6.

Đây là ví dụ đơn giản nhất:

var clonedObjArray = [...oldObjArray];

Bằng cách này, chúng tôi trải mảng thành các giá trị riêng lẻ và đặt nó vào một mảng mới với toán tử [].

Đây là một ví dụ dài hơn cho thấy các cách khác nhau mà nó hoạt động:

let objArray = [ {a:1} , {b:2} ];

let refArray = objArray; // this will just point to the objArray
let clonedArray = [...objArray]; // will clone the array

console.log( "before:" );
console.log( "obj array" , objArray );
console.log( "ref array" , refArray );
console.log( "cloned array" , clonedArray );

objArray[0] = {c:3};

console.log( "after:" );
console.log( "obj array" , objArray ); // [ {c:3} , {b:2} ]
console.log( "ref array" , refArray ); // [ {c:3} , {b:2} ]
console.log( "cloned array" , clonedArray ); // [ {a:1} , {b:2} ]


2
Câu trả lời hiện đại tốt, sẽ không hoạt động với các trình duyệt cũ hơn (như IE 11)
Jealie

1
@Jealie Tôi sẽ đoán KingpinEX đang nhắm mục tiêu câu trả lời này cho những người đang dịch mã es6 sang một thứ gì đó hữu dụng hơn với Babel hoặc những gì có bạn.
ruffin

61
Điều này chỉ sao chép sâu mảng, không phải từng đối tượng trong mảng.
Toivo Säwén

31
Để theo dõi những gì @ ToivoSäwén nói, điều này sẽ không sao chép sâu các đối tượng trong mảng. Nó vẫn sẽ tham chiếu các đối tượng ban đầu vì vậy nếu bạn biến đổi chúng, nó cũng sẽ tác động đến mảng ban đầu.
Joel Kinzel

3
Nó chỉ hoạt động cho người nguyên thủy. Hãy thử điều này: objArray [0] .a = 3; và bạn sẽ thấy tham chiếu của đối tượng vẫn giữ nguyên trong cloneArray.
Sergio Correa

25

Điều này làm việc cho tôi:

var clonedArray = $.map(originalArray, function (obj) {
                      return $.extend({}, obj);
                  });

Và nếu bạn cần sao chép sâu các đối tượng trong mảng:

var clonedArray = $.map(originalArray, function (obj) {
                      return $.extend(true, {}, obj);
                  });

1
Điều này có vẻ như nó sẽ làm việc. Tôi đang cố gắng tránh sử dụng jQuery rộng rãi, vì vậy tôi sẽ không sử dụng nó trong tình huống của mình, nhưng một vòng lặp for và ... trong sẽ hoạt động.
bozdoz

19
$.evalJSON($.toJSON(origArray));

2
Bạn sẽ cần phải được sử dụng jquery json plugin để sử dụng này code.google.com/p/jquery-json
wmitchell

32
Không có JQ (tốt trong các trình duyệt hiện đại):JSON.parse(JSON.stringify(origArray));
forresto

Tôi thấy nhận xét này hữu ích. Trong quá trình thực hiện, tôi cần tạo một bản sao của một loạt các đối tượng có các thuộc tính quan sát được KnockoutJS được áp dụng. Bản sao chỉ cần các giá trị, không phải là quan sát được. Để tạo một bản sao CHỈ các giá trị tôi đã sử dụng JSON.parse (ko.toJSON (origArray)) HOẶC ko.utils.parseJson (ko.toJSON (origArray)). Chỉ cần 2 xu của tôi và cảm ơn bạn đã giúp tôi đi đến giải pháp của mình.
vẫy tay vào

6
JSON.parse(JSON.stringify(origArray));chắc chắn là giải pháp đơn giản nhất.
yorkw

jQuery thường không cần thiết. youmightnotneedjquery.com
ADJenks

9

Bản đồ sẽ tạo mảng mới từ mảng cũ (không tham chiếu đến mảng cũ) và bên trong bản đồ, bạn tạo đối tượng mới và lặp lại các thuộc tính (khóa) và gán các giá trị từ đối tượng Array cũ cho các thuộc tính coresponding cho đối tượng mới.

Điều này sẽ tạo ra chính xác cùng một mảng các đối tượng.

let newArray = oldArray.map(a => {
               let newObject = {};
               Object.keys(a).forEach(propertyKey => {
                    newObject[propertyKey] = a[propertyKey];
               });
               return newObject ;
});

8

Tôi có thể có một cách đơn giản để làm điều này mà không phải thực hiện đệ quy đau đớn và không biết tất cả các chi tiết tốt hơn của đối tượng trong câu hỏi. Sử dụng jQuery, chỉ cần chuyển đổi đối tượng của bạn thành JSON bằng jQuery $.toJSON(myObjectArray), sau đó lấy chuỗi JSON của bạn và đánh giá nó trở lại một đối tượng. BAM! Ngay và luôn! Vấn đề được giải quyết. :)

var oldObjArray = [{ Something: 'blah', Cool: true }];
var newObjArray = eval($.toJSON(oldObjArray));

21
Một số trình duyệt hiện đại có phương thức JSON tích hợp sẵn để bạn có thể thực hiện việc này: JSON.parse (JSON.opesify (MY_ARRAY)) sẽ nhanh hơn. Gợi ý tốt.
Nicolas R

1
Và nếu họ không sử dụng json2 thì không eval.
kamranicus

Điều này có hiệu suất khủng khiếp, nhưng thật không may là câu trả lời hay nhất tôi từng thấy: /
Dvid Silva

Đừng đánh giá bất cứ điều gì với dữ liệu người dùng. Tốt nhất là không bao giờ sử dụng eval()cả. Đó là một rủi ro bảo mật.
ADJenks

8

Tôi đang trả lời câu hỏi này vì dường như không có một giải pháp đơn giản và rõ ràng nào cho vấn đề "nhân bản một mảng các đối tượng trong Javascript":

function deepCopy (arr) {
    var out = [];
    for (var i = 0, len = arr.length; i < len; i++) {
        var item = arr[i];
        var obj = {};
        for (var k in item) {
            obj[k] = item[k];
        }
        out.push(obj);
    }
    return out;
}

// test case

var original = [
    {'a' : 1},
    {'b' : 2}
    ];

var copy = deepCopy(original);

// change value in copy
copy[0]['a'] = 'not 1';

// original[0]['a'] still equals 1

Giải pháp này lặp lại các giá trị mảng, sau đó lặp lại các khóa đối tượng, lưu cái sau vào một đối tượng mới và sau đó đẩy đối tượng mới đó sang một mảng mới.

Xem jsfiddle . Lưu ý: đơn giản .slice()hoặc [].concat()không đủ cho các đối tượng trong mảng.


cảm ơn vì câu trả lời, nhưng bạn nên nhấn mạnh những thiếu sót của câu trả lời. Nó không hoạt động khi các đối tượng có đối tượng trong đó .. phải không?
Harsh

nó sẽ tạo ra bản sao nông. không sâu
sultan aslam

bạn cần thêm đệ quy ở đâu đó
DGoiko

6

Phần mở rộng JQuery đang hoạt động tốt, chỉ cần bạn xác định rằng bạn đang sao chép một mảng chứ không phải là một đối tượng ( lưu ý [] thay vì {} làm tham số cho phương thức mở rộng ):

var clonedNodesArray = jQuery.extend([], nodesArray);

2
Hmm, nếu bạn downvote này, bạn có thể vui lòng thêm một nhận xét về lý do tại sao bạn làm như vậy? Hoặc trước tiên bạn có thể thử mã và xem nó có hoạt động hay không? Cảm ơn;)
Stef

1
Sau khi thay đổi một đối tượng trong mảng đầu tiên, đối tượng trong mảng thứ hai sẽ được sửa đổi, vì vậy nó không ổn.
Spikolynn

6

Phương pháp này rất đơn giản và bạn có thể sửa đổi bản sao của mình mà không sửa đổi mảng ban đầu.

// Original Array
let array = [{name: 'Rafael'}, {name: 'Matheus'}];

// Cloning Array
let clone = array.map(a => {return {...a}})

// Editing the cloned array
clone[1].name = 'Carlos';


console.log('array', array)
// [{name: 'Rafael'}, {name: 'Matheus'}]

console.log('clone', clone)
// [{name: 'Rafael'}, {name: 'Carlos'}]


1
Đây là một bản sao nông sâu hai cấp độ sâu, trong khi đó [...oldArray]oldArray.slice(0)một bản sao nông sâu một cấp độ sâu. Vì vậy, điều này là siêu hữu ích, nhưng không phải là một bản sao đầy đủ sâu thực tế.
Ben Wheeler

bản sao sâu thực sự có thể được thực hiện bằng cách sử dụng lodash.clonedeeptừ
npm

5

Như Daniel Lew đã đề cập, đồ thị theo chu kỳ có một số vấn đề. Nếu tôi gặp vấn đề này, tôi sẽ thêm các clone()phương thức đặc biệt vào các đối tượng có vấn đề hoặc nhớ những đối tượng tôi đã sao chép.

Tôi sẽ làm điều đó với một biến copyCounttăng 1 mỗi lần bạn sao chép mã của mình. Một đối tượng có mức thấp hơncopyCount quá trình sao chép hơn hiện tại được sao chép. Nếu không, bản sao, đã tồn tại, nên được tham khảo. Điều này làm cho nó cần thiết để liên kết từ bản gốc đến bản sao của nó.

Vẫn còn một vấn đề: Bộ nhớ. Nếu bạn có tham chiếu này từ đối tượng này sang đối tượng khác, có khả năng trình duyệt không thể giải phóng những đối tượng đó, vì chúng luôn được tham chiếu từ đâu đó. Bạn sẽ phải vượt qua lần thứ hai nơi bạn đặt tất cả các tham chiếu sao chép thành Null. (Nếu bạn làm điều này, bạn không cần phải có copyCountmột boolean isCopiedlà đủ, vì bạn có thể đặt lại giá trị trong lần chuyển thứ hai.)


4

Array.slice có thể được sử dụng để sao chép một mảng hoặc một phần của một mảng .. http://www.devguru.com/Technology/Ecmascript/Quickref/Slice.html Điều này sẽ hoạt động với chuỗi và số .. - thay đổi một chuỗi trong một mảng sẽ không ảnh hưởng đến mảng kia - nhưng các đối tượng vẫn chỉ được sao chép bởi tham chiếu nên các thay đổi đối với các đối tượng được tham chiếu trong một mảng sẽ có ảnh hưởng đến mảng khác.

Dưới đây là một ví dụ về trình quản lý hoàn tác JavaScript có thể hữu ích cho việc này: http://www.ridgway.co.za/archive/2007/11/07/simple-javascript-undo-manager-for-dtos.aspx


Tôi biết. Lý do tôi muốn thực hiện điều này là vì tôi đang cố gắng giải quyết vấn đề CSP bằng cách quay lại. Tôi nghĩ rằng một trong những cách thực hiện quay lui có thể giống như "chụp ảnh nhanh" trạng thái gán các biến bằng cách ... sao chép các ảnh chụp nhanh như vậy vào một ngăn xếp.
wallyqs

... Và tốt, nó thực sự có thể là một ý tưởng rất tồi.
wallyqs

Cách tiếp cận đó có thể có các biến chứng đồng bộ hóa khác :) .. Làm thế nào để bạn biết mảng không bị thay đổi trong khi bạn chụp ảnh nhanh?
Markt

Đã thêm một liên kết đến một bài viết trong đó tác giả đã triển khai trình quản lý hoàn tác đơn giản bằng cách sử dụng javascript ..
markt

4

Cách tiếp cận của tôi:

var temp = { arr : originalArray };
var obj = $.extend(true, {}, temp);
return obj.arr;

cung cấp cho tôi một bản sao đẹp, rõ ràng, sâu sắc của mảng ban đầu - không có đối tượng nào được tham chiếu trở lại bản gốc :-)


Đây là giải pháp tốt nhất bằng cách sử dụng jquery. ngắn và ngọt.
John Henckel

1
Tôi đã thực hiện một bài kiểm tra hiệu năng và giải pháp này dường như nhanh hơn khoảng 2 lần so với giải pháp JSON.opesify.
meehocz

4

lodash có cloneDeepchức năng cho mục đích này:

var objects = [{ 'a': 1 }, { 'b': 2 }];
var deep = _.cloneDeep(objects);

4

Nếu bạn muốn triển khai bản sao sâu, hãy sử dụng JSON.parse (JSON.opesify ({} hoặc []))

const myObj ={
    a:1,
    b:2,
    b:3
}

const deepClone=JSON.parse(JSON.stringify(myObj));
deepClone.a =12;
console.log("deepClone-----"+myObj.a);
const withOutDeepClone=myObj;
withOutDeepClone.a =12;
console.log("withOutDeepClone----"+myObj.a);


3

quên eval () (là tính năng bị lạm dụng nhiều nhất của JS và làm cho mã chậm) và lát (0) (chỉ hoạt động cho các loại dữ liệu đơn giản)

Đây là giải pháp tốt nhất cho tôi:

Object.prototype.clone = function() {
  var myObj = (this instanceof Array) ? [] : {};
  for (i in this) {
    if (i != 'clone') {
        if (this[i] && typeof this[i] == "object") {
          myObj[i] = this[i].clone();
        } else 
            myObj[i] = this[i];
        } 
    }
  return myObj;
};

3

Tôi đã khá thất vọng bởi vấn đề này. Rõ ràng vấn đề phát sinh khi bạn gửi một Mảng chung cho phương thức $ .extend. Vì vậy, để khắc phục nó, tôi đã thêm một kiểm tra nhỏ và nó hoạt động hoàn hảo với các mảng chung, mảng jQuery và bất kỳ đối tượng nào.

jQuery.extend({
    deepclone: function(objThing) {
        // return jQuery.extend(true, {}, objThing);
        /// Fix for arrays, without this, arrays passed in are returned as OBJECTS! WTF?!?!
        if ( jQuery.isArray(objThing) ) {
            return jQuery.makeArray( jQuery.deepclone($(objThing)) );
        }
        return jQuery.extend(true, {}, objThing);
    },
});

Gọi bằng cách sử dụng:

var arrNewArrayClone = jQuery.deepclone(arrOriginalArray);
// Or more simply/commonly
var arrNewArrayClone = $.deepclone(arrOriginalArray);

sâu? Tôi sử dụng jquery-1.9.1 và nó không hỗ trợ phương pháp này. Đây có phải là phương pháp của phiên bản hiện đại hơn?
dùng5260143

@ user2783091 anh ấy đang mở rộng JQuery để thêm chức năng đó. Đó không phải là thứ gì đó xuất hiện
JorgeeFG

3

Điều này sao chép sâu các mảng, đối tượng, null và các giá trị vô hướng khác, và cũng sao chép sâu bất kỳ thuộc tính nào trên các hàm không phải là nguồn gốc (điều này không phổ biến nhưng có thể). (Để hiệu quả, chúng tôi không cố gắng sao chép các thuộc tính không phải là số trên mảng.)

function deepClone (item) {
  if (Array.isArray(item)) {
    var newArr = [];
    for (var i = item.length; i-- > 0;) {
      newArr[i] = deepClone(item[i]);
    }
    return newArr;
  }
  if (typeof item === 'function' && !(/\(\) \{ \[native/).test(item.toString())) {
    var obj;
    eval('obj = '+ item.toString());
    for (var k in item) {
      obj[k] = deepClone(item[k]);
    }
    return obj;
  }
  if (item && typeof item === 'object') {
    var obj = {};
    for (var k in item) {
      obj[k] = deepClone(item[k]);
    }
    return obj;
  }
  return item;
}

3

Tôi sử dụng phương thức Object.assign ECMAScript 6 mới :

let oldObject = [1,3,5,"test"];
let newObject = Object.assign({}, oldObject);

đối số đầu tiên của phương thức này là mảng được cập nhật, chúng ta truyền một đối tượng trống vì chúng ta muốn có một đối tượng mới.

chúng ta cũng có thể sử dụng cú pháp này, tương tự nhưng ngắn hơn:

let newObject = [...oldObject];

Lưu ý rằng các phương pháp này sẽ chỉ sao chép các tham chiếu cho các mảng và các đối tượng trong mảng và sẽ không tạo các bản sao mới của các mảng này. Hy vọng điều này sẽ phá vỡ cho các cấu trúc đa chiều.
Ben Wheeler

2

Chúng ta có thể phát minh ra một phương thức Mảng đệ quy đơn giản để sao chép các mảng nhiều chiều. Trong khi các đối tượng trong các mảng lồng nhau giữ tham chiếu đến các đối tượng tương ứng trong mảng nguồn, thì các mảng sẽ không.

Array.prototype.clone = function(){
  return this.map(e => Array.isArray(e) ? e.clone() : e);
};

var arr = [ 1, 2, 3, 4, [ 1, 2, [ 1, 2, 3 ], 4 , 5], 6 ],
    brr = arr.clone();
brr[4][2][1] = "two";
console.log(JSON.stringify(arr));
console.log(JSON.stringify(brr));


2

Trong JavaScript, bản sao mảng và đối tượng thay đổi các giá trị gốc, vì vậy Deep copy là giải pháp cho việc này.

Một bản sao sâu có nghĩa là thực sự tạo ra một mảng mới và sao chép các giá trị, vì bất cứ điều gì xảy ra với nó sẽ không bao giờ ảnh hưởng đến nguồn gốc.

JSON.parseJSON.stringifylà cách tốt nhất và đơn giản để sao chép sâu. Các JSON.stringify()cải cách một giá trị hoạt Javascript để một JSON string.The JSON.parse()phương pháp phân tích một chuỗi JSON, xây dựng giá trị JavaScript hoặc đối tượng được mô tả bởi chuỗi.

// Bản sao sâu

let a = [{ x:{z:1} , y: 2}];
let b = JSON.parse(JSON.stringify(a));
b[0].x.z=0

console.log(JSON.stringify(a)); //[{"x":{"z":1},"y":2}]
console.log(JSON.stringify(b)); // [{"x":{"z":0},"y":2}]

Để biết thêm chi tiết: Đọc tại đây


1
Đây là giải pháp tốt nhất. Cảm ơn bạn.
Nikolay

1

với jQuery:

var target= [];
$.each(source, function() {target.push( $.extend({},this));});

1

Đoạn mã sau sẽ thực hiện đệ quy một bản sao sâu của các đối tượng và mảng :

function deepCopy(obj) {
if (Object.prototype.toString.call(obj) === '[object Array]') {
    var out = [], i = 0, len = obj.length;
    for ( ; i < len; i++ ) {
        out[i] = arguments.callee(obj[i]);
    }
    return out;
}
if (typeof obj === 'object') {
    var out = {}, i;
    for ( i in obj ) {
        out[i] = arguments.callee(obj[i]);
    }
    return out;
}
return obj;
}

Nguồn


arguments.calleekhông có sẵn trong chế độ nghiêm ngặt và có vấn đề về hiệu suất khác.
Brett Zamir


0

Tôi nghĩ đã quản lý để viết một phương pháp chung để nhân bản sâu bất kỳ cấu trúc JavaScript nào, chủ yếu sử dụng Object.createđược hỗ trợ trong tất cả các trình duyệt hiện đại. Mã này là như thế này:

function deepClone (item) {
  if (Array.isArray(item)) {
    var newArr = [];

    for (var i = item.length; i-- !== 0;) {
      newArr[i] = deepClone(item[i]);
    }

    return newArr;
  }
  else if (typeof item === 'function') {
    eval('var temp = '+ item.toString());
    return temp;
  }
  else if (typeof item === 'object')
    return Object.create(item);
  else
    return item;
}

Object.createsẽ coi itemnhư nguyên mẫu của đối tượng, nhưng khác với nhân bản. Nếu itemđược sửa đổi, các thay đổi sẽ được phản ánh trong "bản sao" của nó và ngược lại. Cách tiếp cận này không hoạt động.
Brett Zamir

0

Để nhân bản các đối tượng, tôi chỉ đề xuất ECMAScript 6 reduce():

const newArray=myArray.reduce((array, element)=>array.push(Object.assign({}, element)), []);

Nhưng thẳng thắn, tôi thích câu trả lời của @dinodsaurus thậm chí còn tốt hơn. Tôi chỉ đặt phiên bản này ở đây làm tùy chọn khác, nhưng cá nhân tôi sẽ sử dụng map()theo đề xuất của @dinodsaurus.



0
       var game_popularity = [
            { game: "fruit ninja", popularity: 78 },
            { game: "road runner", popularity: 20 },
            { game: "maze runner", popularity: 40 },
            { game: "ludo", popularity: 75 },
            { game: "temple runner", popularity: 86 }
        ];
        console.log("sorted original array before clonning");
        game_popularity.sort((a, b) => a.popularity < b.popularity);
        console.log(game_popularity);


        console.log("clone using object assign");
        const cl2 = game_popularity.map(a => Object.assign({}, a));
        cl2[1].game = "clash of titan";
        cl2.push({ game: "logan", popularity: 57 });
        console.log(cl2);


        //adding new array element doesnt reflect in original array
        console.log("clone using concat");
        var ph = []
        var cl = ph.concat(game_popularity);

        //copied by reference ?
        cl[0].game = "rise of civilization";

        game_popularity[0].game = 'ping me';
        cl.push({ game: "angry bird", popularity: 67 });
        console.log(cl);

        console.log("clone using ellipses");
        var cl3 = [...game_popularity];
        cl3.push({ game: "blue whale", popularity: 67 });
        cl3[2].game = "harry potter";
        console.log(cl3);

        console.log("clone using json.parse");
        var cl4 = JSON.parse(JSON.stringify(game_popularity));
        cl4.push({ game: "home alone", popularity: 87 });
        cl4[3].game ="lockhead martin";
        console.log(cl4);

        console.log("clone using Object.create");
        var cl5 = Array.from(Object.create(game_popularity));
        cl5.push({ game: "fish ville", popularity: 87 });
        cl5[3].game ="veto power";
        console.log(cl5);


        //array function
        console.log("sorted original array after clonning");
        game_popularity.sort((a, b) => a.popularity < b.popularity);
        console.log(game_popularity);


        console.log("Object.assign deep clone object array");
        console.log("json.parse deep clone object array");
        console.log("concat does not deep clone object array");
        console.log("ellipses does not deep clone object array");
        console.log("Object.create does not deep clone object array");


        Output:


        sorted original array before clonning
        [ { game: 'temple runner', popularity: 86 },
        { game: 'fruit ninja', popularity: 78 },
        { game: 'ludo', popularity: 75 },
        { game: 'maze runner', popularity: 40 },
        { game: 'road runner', popularity: 20 } ]
        clone using object assign
        [ { game: 'temple runner', popularity: 86 },
        { game: 'clash of titan', popularity: 78 },
        { game: 'ludo', popularity: 75 },
        { game: 'maze runner', popularity: 40 },
        { game: 'road runner', popularity: 20 },
        { game: 'logan', popularity: 57 } ]
        clone using concat
        [ { game: 'ping me', popularity: 86 },
        { game: 'fruit ninja', popularity: 78 },
        { game: 'ludo', popularity: 75 },
        { game: 'maze runner', popularity: 40 },
        { game: 'road runner', popularity: 20 },
        { game: 'angry bird', popularity: 67 } ]
        clone using ellipses
        [ { game: 'ping me', popularity: 86 },
        { game: 'fruit ninja', popularity: 78 },
        { game: 'harry potter', popularity: 75 },
        { game: 'maze runner', popularity: 40 },
        { game: 'road runner', popularity: 20 },
        { game: 'blue whale', popularity: 67 } ]
        clone using json.parse
        [ { game: 'ping me', popularity: 86 },
        { game: 'fruit ninja', popularity: 78 },
        { game: 'harry potter', popularity: 75 },
        { game: 'lockhead martin', popularity: 40 },
        { game: 'road runner', popularity: 20 },
        { game: 'home alone', popularity: 87 } ]
        clone using Object.create
        [ { game: 'ping me', popularity: 86 },
        { game: 'fruit ninja', popularity: 78 },
        { game: 'harry potter', popularity: 75 },
        { game: 'veto power', popularity: 40 },
        { game: 'road runner', popularity: 20 },
        { game: 'fish ville', popularity: 87 } ]
        sorted original array after clonning
        [ { game: 'ping me', popularity: 86 },
        { game: 'fruit ninja', popularity: 78 },
        { game: 'harry potter', popularity: 75 },
        { game: 'veto power', popularity: 40 },
        { game: 'road runner', popularity: 20 } ]

        Object.assign deep clone object array
        json.parse deep clone object array
        concat does not deep clone object array
        ellipses does not deep clone object array
        Object.create does not deep clone object array
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.