Как вы клонируете массив объектов в Javascript? - PullRequest
365 голосов
/ 28 февраля 2009

... где каждый объект также имеет ссылки на другие объекты в том же массиве?

Когда я впервые столкнулся с этой проблемой, я просто подумал о чем-то вроде

var clonedNodesArray = nodesArray.clone()

будет существовать и искать информацию о том, как клонировать объекты в JavaScript. Я нашел вопрос в StackOverflow (на который ответил тот же @JohnResig), и он указал, что с jQuery вы можете сделать

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

для клонирования объекта. Я попробовал это, хотя, это только копирует ссылки на объекты в массиве. Так что, если я

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

значение обоих nodeArray [0] и clonedNodesArray [0] окажется "зеленым". Тогда я попробовал

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

, который глубоко копирует Объект, но я получил сообщения " слишком много рекурсии " и " переполнение стека управления " от Firebug и Opera Dragonfly соответственно.

Как бы вы это сделали? Это что-то, что даже не следует делать? Есть ли способ повторного использования в Javascript?

Ответы [ 30 ]

2 голосов
/ 16 июня 2016

Мы можем изобрести простой рекурсивный метод Array для клонирования многомерных массивов. В то время как объекты во вложенных массивах сохраняют свои ссылки на соответствующие объекты в исходном массиве, массивы не будут.

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));
1 голос
/ 21 марта 2017

Несколько элегантных способов глубокого клонирования в javascript

https://mootools.net/core/docs/1.6.0/Types/Object

https://scotch.io/bar-talk/copying-objects-in-javascript

1) Ванильный метод Javascript для клонирования объектов

2) Умное использование библиотеки JSON для глубоко клонированных объектов

3) Использование функции $ .extend () в jQuery

4) Использование функции clone () в Mootools для клонирования объектов

1 голос
/ 25 марта 2013

Следующий код рекурсивно выполнит глубокое копирование объектов и массива :

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

Источник

1 голос
/ 03 апреля 2012

с jQuery:

var target= [];
$.each(source, function() {target.push( $.extend({},this));});
0 голосов
/ 18 марта 2018
       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
0 голосов
/ 13 февраля 2018
function deepCloneArray(array) {
    return Array.from(Object.create(array));
}
0 голосов
/ 10 февраля 2017

В зависимости от того, есть ли у вас Underscore или Babel, здесь есть эталон другого способа глубокого клонирования массива.

https://jsperf.com/object-rest-spread-vs-clone/2

Похоже, что Babel самый быстрый.

var x = babel({}, obj)
0 голосов
/ 01 февраля 2017

Также для клонирования объектов я собирался предложить ECMAScript 6 reduce():

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

Но, честно говоря, мне больше нравится ответ @dinodsaurus. Я просто выкладываю эту версию здесь как еще один вариант, но лично я буду использовать map(), как предложено @dinodsaurus.

0 голосов
/ 23 мая 2019

В JavaScript копирование массива и объекта изменяет исходные значения, поэтому для этого рекомендуется использовать Deep copy.

Глубокая копия означает фактическое создание нового массива и копирование значений, поскольку все, что с ним происходит, никогда не повлияет на исходный.

JSON.parse и JSON.stringify - лучший и простой способ глубокого копирования. Метод JSON.stringify() преобразует значение JavaScript в строку JSON. Метод JSON.parse() анализирует строку JSON, создавая значение JavaScript или объект, описываемый строкой.

// Глубокий клон

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

Для более подробной информации: Читать здесь

0 голосов
/ 04 июня 2015

Я думаю, что удалось написать общий метод глубокого клонирования любой структуры JavaScript, в основном с использованием Object.create, который поддерживается во всех современных браузерах. Код такой:

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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...