Pull to refresh

Объединение объектов(v 1.1)

Reading time3 min
Views11K
Привет Хабр!
Буквально вчера возникла необходимость объединить два объекта javascript. Покопавшись в интернетах узнал, что единственный способ объединить два объекта это скопировать поля из одного в другой. («Разрывная» — подумал Штирлиц) Пораскинув мозгами создал свой велосипед метод для этого дела.

Основные возможности:
  1. копирование свойств одного объекта в другой с рекурсивным обходом последнего, на выходе имеем объект, содержащий в себе все свойства первого и второго.
  2. копирование свойств без рекурсивного обхода объекта-источника, в этом случае на выходе будет объект, сохраняющий исходную структуру первого и второго объекта
  3. на случай если у двух объектов есть свойства с одинаковым именем предусмотрено два варианта развития событий:
    1. с сохранением обоих свойств — формируется массив значений
    2. с заменой исходного целевым

  4. Ограничение глубины копирования

Ну и собственно сама функция:

/**
    *Функция копирования свойств одного объекта в другой
    * @param objS <i>object</i> объект из которого будут копироваться свойства
    * @param objT <i>&object</i> объект в который будут копироваться свойства
    * @param rec <i>bool</i> флаг рекурсивного обхода объекта-источника для полного
    * переноса всех свойств иначе поля будут скопированы "как есть"
    * @param repl <i>bool</i> флаг замены значений свойств с одинаковым именем
    * если он не определен - будет созддан массив значений
    * @param max_l_rec <i>int</i> максимальная глубина рекурсии(изменять с осторожностью)
    * при значении 1 объекты копируются "как есть"
    */
function objUnion(objS, objT, rec, repl, max_l_rec)
{
    //считаем число элементов в исходном объекте
    var count_elem = objS.length;

    //для контроля рекурсии создадим у целевого объекта два служебных поля,
    //первое - глубина рекурсии, второе - количество посчитанных элементов,
    //дабы знать, когда достигнут конец копирования и означенные поля можно удалять
    if(!objT.hasOwnProperty("cur_l_rec"))
    {
        objT.cur_l_rec = 0;
        objT.summ_elem = 0;

        var cur_l_rec = 0;
    }
    else
    {
        objT.cur_l_rec++;
        cur_l_rec = objT.cur_l_rec;
    }

    //если достигнут максимальный уровень рекурсии
    if(max_l_rec && objT.cur_l_rec == max_l_rec)
    {
        objUnion(objS, objT, rec, repl, max_l_rec);
        delete objT.cur_l_rec ;
        return;
    }
    //начинаем копировать
    for(var key in objS)
    {

        //если текущее поле является объектом
        //и определен параметр рекурсивного обхода - заглянем внутрь него
        if(typeof(objS[key]) == 'object')
        {
            if(rec && ((max_l_rec && objT.cur_l_rec < max_l_rec)|| !max_l_rec))
            {
                objUnion(objS[key], objT, rec, repl, max_l_rec);
				objT.cur_l_rec = cur_l_rec;
				//если мы вернулись из глубин прибавляем к скопированным элементам единичку
				if(objT.cur_l_rec == 0)
				{
					objT.summ_elem ++;
				}
                continue;
            }
        }
        //определяем, что делать с полями, имеющими одинаковое имя
        //либо создаем из них массив, либо меняем значение первого на второе
        if(objT[key] && !repl)
        {
            objT[key] = [objS[key],objT[key]];
        }
        else
        {
            objT[key] = objS[key];
        }
    }

    //если скопированы свой свойства всех объектов убираем служебные поля
    if((objT.summ_elem == count_elem || !objS.hasOwnProperty('length')) && (objT.cur_l_rec == 0 && cur_l_rec == 0))
    {
        delete objT.cur_l_rec ;
        delete objT.summ_elem ;
    }
}

//небольшой тест
var obj1 = [
	{
		field4 : {
			field9 : {
				field10 : 1
			}, field8 : 2
		},
		field5 : 3
	},
	{
		field6 : 5,
		field7 : {
			field11 : 'green',
			field12 : 'black'
		}
	},
	{
		field13 : 5,
		field14 : {
			field15 : 'green',
			field16 : 'black'
		}
	}
];
var obj2 = {
	field1 : 'green',
	field2 : 'square',
	field3 : 'small'
};


//ссылка на объект в который будет копироваться
var link = obj2
objUnion(obj1, link, 1, 0, 1);
//удяляем ссылку
link = null;
console.log(obj2);


Всех благодарю за внимание, надеюсь, мой велосипед метод будет кому-то полезен.

Существует решение этой проблемы с помощью jQuery и функции extend, но не подключать же целый фреймворк ради использования одной функции.

P.S. огромная просьба, если вам не понравилась моя функция напишите в комментариях КОНКРЕТНО, что в ней плохого, с удовольствием поправлю, на хорошее.
Tags:
Hubs:
Total votes 22: ↑6 and ↓16-10
Comments49

Articles