(Глубокое) копирование массива с помощью jQuery

Возможный дубликат:
Каков наиболее эффективный способ клонирования объекта JavaScript?

Мне нужно скопировать (упорядоченный, не ассоциативный) массив объектов. Я использую jQuery. Сначала я попробовал

jquery.extend({}, myArray)

но, естественно, это возвращает мне объект, где мне нужен массив (на самом деле, люблю jquery.extend).

Итак, что лучший способ скопировать массив?

Ответ 1

Так как Array.slice() не выполняет глубокое копирование, он не подходит для многомерных массивов:

var a =[[1], [2], [3]];
var b = a.slice();

b.shift().shift();
// a is now [[], [2], [3]]

Обратите внимание, что хотя я использовал shift().shift() выше, точка в том, что b[0][0] содержит указатель на a[0][0], а не значение.

Аналогично delete(b[0][0]) также вызывает удаление a[0][0], а b[0][0]=99 также изменяет значение a[0][0] на 99.

jQuery extend метод выполняет глубокую копию, когда истинное значение передается как начальный аргумент:

var a =[[1], [2], [3]];
var b = $.extend(true, [], a);

b.shift().shift();
// a is still [[1], [2], [3]]

Ответ 2

$.extend(true, [], [['a', ['c']], 'b'])

Это должно сделать это для вас.

Ответ 3

Я понимаю, что вы ищете "глубокую" копию массива, но если у вас есть только один уровень, вы можете использовать это:

Копирование собственного массива JS легко. Используйте метод Array.slice(), который создает копию части/всего массива.

var foo = ['a','b','c','d','e'];
var bar = foo.slice();

теперь foo и bar являются 5-членными массивами 'a', 'b', 'c', 'd', 'e'

Конечно, бар - это копия, а не ссылка... так что если вы сделали следующее...

bar.push('f');
alert('foo:' + foo.join(', '));
alert('bar:' + bar.join(', '));

вы бы получили:

foo:a, b, c, d, e
bar:a, b, c, d, e, f

Ответ 4

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

Ответ 5

Если вы хотите использовать чистый JavaScript, попробуйте следующее:

 var arr=["apple","ball","cat","dog"];
 var narr=[];

 for(var i=0;i<arr.length;i++){
     narr.push(arr[i]);
 }
 alert(narr); //output: apple,ball,vat,dog
 narr.push("elephant");
 alert(arr); // output: apple,ball,vat,dog
 alert(narr); // apple,ball,vat,dog,elephant

Ответ 7

Я планирую выпустить этот код в следующей версии jPaq, но до тех пор вы можете использовать это, если ваша цель - сделать глубокую копию массивов:

Array.prototype.clone = function(doDeepCopy) {
    if(doDeepCopy) {
        var encountered = [{
            a : this,
            b : []
        }];

        var item,
            levels = [{a:this, b:encountered[0].b, i:0}],
            level = 0,
            i = 0,
            len = this.length;

        while(i < len) {
            item = levels[level].a[i];
            if(Object.prototype.toString.call(item) === "[object Array]") {
                for(var j = encountered.length - 1; j >= 0; j--) {
                    if(encountered[j].a === item) {
                        levels[level].b.push(encountered[j].b);
                        break;
                    }
                }
                if(j < 0) {
                    encountered.push(j = {
                        a : item,
                        b : []
                    });
                    levels[level].b.push(j.b);
                    levels[level].i = i + 1;
                    levels[++level] = {a:item, b:j.b, i:0};
                    i = -1;
                    len = item.length;
                }
            }
            else {
                levels[level].b.push(item);
            }

            if(++i == len && level > 0) {
                levels.pop();
                i = levels[--level].i;
                len = levels[level].a.length;
            }
        }

        return encountered[0].b;
    }
    else {
        return this.slice(0);
    }
};

Ниже приведен пример того, как вызвать эту функцию для глубокой копии рекурсивного массива:

// Create a recursive array to prove that the cloning function can handle it.
var arrOriginal = [1,2,3];
arrOriginal.push(arrOriginal);

// Make a shallow copy of the recursive array.
var arrShallowCopy = arrOriginal.clone();

// Prove that the shallow copy isn't the same as a deep copy by showing that
// arrShallowCopy contains arrOriginal.
alert("It is " + (arrShallowCopy[3] === arrOriginal)
    + " that arrShallowCopy contains arrOriginal.");

// Make a deep copy of the recursive array.
var arrDeepCopy = arrOriginal.clone(true);

// Prove that the deep copy really works by showing that the original array is
// not the fourth item in arrDeepCopy but that this new array is.
alert("It is "
    + (arrDeepCopy[3] !== arrOriginal && arrDeepCopy === arrDeepCopy[3])
    + " that arrDeepCopy contains itself and not arrOriginal.");

Вы можете поиграть с этим кодом здесь, в JS Bin.

Ответ 8

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

Мой вариант:

Object.prototype.copy = function(){
    var v_newObj = {};
    for(v_i in this)
        v_newObj[v_i] = (typeof this[v_i]).contains(/^(array|object)$/) ? this[v_i].copy() : this[v_i];
    return v_newObj;
}

Array.prototype.copy = function(){
    var v_newArr = [];
    this.each(function(v_i){
        v_newArr.push((typeof v_i).contains(/^(array|object)$/) ? v_i.copy() : v_i);
    });
    return v_newArr;
}

Это не окончательная версия, просто идея.

PS: каждый метод и содержит также прототипы.