Clone Javascript object

В javascript объекты передаются и копируются по ссылке. Рассмотрим пример:

// Создаем объект с единственным полем number
var obj = { number: 1 };

// Копируем объект
var copy = obj;
copy.number = 777;

alert(obj.number);

В результате выполнения данного кода на экран будет выведено число 777 (а не 1 как ожидалось). Переменные obj и copy – одна и та же ссылка.

Как передать объект по значению? Нам нужна функция clone.

Я пробовал множество функций, но в них было много недостатков (не копировались методы объекта, или массивы). В итоге нашлась хорошая реализация (из фреймворка ExtJS). Я немного подправил эту функцию, вот результат:

function clone(o) {
 if(!o || ‘object’ !== typeof o)  {
   return o;
 }
 varc = ‘function’ === typeof o.pop ? [] : {};
 var p, v;
 for(p in o) {
 if(o.hasOwnProperty(p)) {
  v = o[p];
  if(v && ‘object’ === typeof v) {
    c[p] = clone(v);
  }
  else {
    c[p] = v;
  }
 }
}
 return c;
}

Проверяем действие функции:

var o = { a:1, get:function(){ alert(this.arr[1]);}, arr: [1,2,3] };
var c = clone(o); // делаем клон объекта

c.arr[0] = 77;
c.arr[1] = 88;
c.arr[2] = 99;

// Значения остались прежними
alert(o.arr[0]); // 1
alert(o.arr[1]); // 2
alert(o.arr[2]); // 3

// Методы тоже были скопированы
c.get(); // 88
o.get(); // 2

Как видно из примера, функция clone скопировала объект o вместе со всеми его свойствами и методами.

Пользуйтесь на здоровье 🙂

  • Согласен. Так удобнее.

  • admin

    @ evol1980:

    Мой блог – это, в первую очередь ресурс для меня, и размещать чужие статьи здесь я не собираюсь.

  • Я вам очень благодарен, мне понравилось.

  • На самом деле, ситуаций, когда нужна одна лишь функция «clone(…)», практически не бывает. В реальных проектах обычно есть функция «extent», а на её основе строят функцию «clone».
    function extend(obj, hash) {
    for(var key in hash)
    if(hash.hasOwnProperty(key))
    obj[key] = hash[key];
    }

    function clone(obj) {
    return extend({}, obj);
    }
    То есть для копирование объекта, создаётся новый объект и расширяется методами и атрибутами переданного.

  • Voland

    Хорошая статья. Спасибо =)

    2Octane: а функция extend не должна возвращать объект??

    return obj;

  • iln

    не должна – объекты передаются по ссылки.

  • Pingback: ШкодеРРу » Blog Archive » Клонирование объектов в JavaScript()

  • Tnanx! Немножко модифицировал.
    http://shcoder.ru/2009/01/23/javascript-utils-clone/

  • Хм… читаю блоги по близкой тематике, а к Вам ни разу не наведывалась, добавила в избранное, я теперь Ваш постоянный читатель 🙂

  • Не понял как сделать, что бы работало 2 копии одного объекта но с разными свойствами?

    У меня работал объект, который подгружал контент в div, теперь пытаюсь использовать этот же класс, что бы подгрузить во второй div.
    Пишу:
    engine.init(null, $(“#d1”), 0 );
    var engine2 = engine;
    engine2.init(null, $(“#d2”), 1);

    А контент выводит во втором div, который должен быть в первом, а в первом вообще пусто.

  • Встретил в гугловском коде похожую функцию (obj target object, vals source object):
    var setVals = function (obj, vals) {
    if (obj && vals) {
    for (var x in vals) {
    if (vals.hasOwnProperty(x)) {
    if (obj[x] && typeof vals[x] === ‘object’) {
    obj[x] = setVals(obj[x], vals[x]);
    } else {
    obj[x] = vals[x];
    }
    }
    }
    }
    return obj;
    };

  • ddosia

    спасибо за пример функции для клонирования, есть небольшое добавление:
    функция клонирует только свойства и методы объекта, но оставляет неизменным его прототип.

    можно заменить:
    var c = ‘function’ === typeof o.pop ? [] : {};

    на:
    var c = []
    if (o.constructor !== Array) {
    function P () {}
    P.prototype = o.constructor.prototype;
    c = new P();
    }

  • Slaffko

    Через JQuery тоже можно вот так:
    $.extend(target, object1, …, objectN);

  • dejavu

    http://oranlooney.com/functional-javascript/

    Клонируйте просто 😉

  • 2 дня убил, пока разобрался
    в jquery есть метод extend, которая объединяет массивы в один объект.
    Чтобы создать точную копию – первым элементом нужно задать пустой объект {}.
    Чтобы рекурсивно скопировать все свойства – первым параметром передается true;
    То есть готовая функция выглядит как
    a=$.extend(true,{},b)

  • Paul Loyd

    Я думаю следует обновить статью до актуального состояния, добавив копирование геттеров и сеттеров.