barbitoff programmer`s blog

Здесь я публикую заметки из программерской жизни: грабли, на которые мне случилось наступить, проблемы, для которых было найдено элегантное (или не очень) решение, а также все, с чем мне пришлось столкнуться и чем хотелось бы поделиться =)
PS Если хотите меня поблагодарить - на странице есть 3 места, чтобы это сделать =)

среда, 25 января 2012 г.

JavaScript: Копирование и объединение объектов

Для копирования объектов и их объединения можно использовать средства Yahoo UI 2:
YAHOO.lang.augmentObject({},obj)
YAHOO.lang.merge(obj1, obj2)
Проблема этих методов в том, что они не выполняют рекурсивное копирование полей объектов в случае, если они сами являются объектами. Проверяется это просто:
var a = {a:{a:"a",b:"b"}}
alert(a.a.a);// выведет "а"
var b = YAHOO.lang.augmentObject({},a);
alert(b.a.a);// выведет "а"
a.a.a = "b"alert(a.a.a);// выведет "b", что естественноalert(b.a.a);// выведет "b", что говорит о том, что поле b.a ссылается реально на тот же объект, что и a.a
В принципе, можно было и не проверять, я просто посмотреть в исходниках, где явно видно, что поля переносятся простым присваиванием (http://developer.yahoo.com/yui/docs/Lang.js.html). Т.к. из тех же исходников видно, что метод merge вызывается augmentObject, и, следовательно, при его использовании полученный объект также будет ссылаться своими полями на теже объекты, что и поля исходных объектов.

Поэтому пришлось написать подобные функции самому (copyObj имеет дополнительный функционал, копируя массивы не как объекты, а как массивы, а также не копируя функции, оставляя их как есть):
/**
 * Копирует объект (рекурсивно)
 * Аналогична YAHOO.lang.augmentObject({},obj), только выполняет копирование полей
 * рекурсивно, т.е. если поле - объект, то он тоже копируется.
 */

function copyObj(obj)
{
    // если передан не объект - копировать не надо, возвращаем значение. Функции тоже не копируем
    if(!(obj instanceof Object) || obj instanceof Function)
        return obj;
    // иначе - производим рекурсивное копирование всех полей (в т.ч. унаследованных). Объекты возвращаем
    // как объекты, массивы - как массивы  
    var ret;
    if(obj instanceof Array)
        ret = new Array();
    else
        ret = Object();

    for(var key in obj)
        ret[key] = copyObj(obj[key]);
    return ret;  
}

/**
 * Объединяет объекты, возвращая новый объект
 * (все поля нового объекта являются копиями (рекурсивными, т.е. полнями)
 * переданных объектов, т.е. изменение переданных объектов никак не повлияет
 * на результат, полученный с помощью данной функции)
 * Аналогична YAHOO.lang.merge, только копирование полей из переданных объектов выполняется
 * рекурсивно (т.е. если поля переданных в качестве аргументов объектов сами являются объектами,
 * они копируются в выходной объект не присваиванием, а вызовом copyObj, которая рекурсивно копирует
 * поле в новый объект)
 * TODO: распространить на любое число объектов-аргументов
 */
function mergeObjects(obj1, obj2)
{
    var ret = copyObj(obj1);
    for(var key in obj2)
        ret[key] = copyObj(obj2[key]);
    return ret;

Комментариев нет:

Отправить комментарий