Привет!
Буквально вчера возникла необходимость объединить два объекта javascript. Каково же было мое удивление, когда оператор + вместо ожидаемого слияния объектов вернул мне строку… Покопавшись в интернетах узнал, что единственный способ объединить два объекта это скопировать поля из одного в другой. («Разрывная» — подумал Штирлиц) Пораскинув мозгами создал свой велосипед метод для этого дела.
Основные возможности:
- копирование свойств одного объекта в другой с рекурсивным обходом последнего, на выходе имеем объект, содержащий в себе все свойства первого и второго.
- копирование свойств без рекурсивного обхода объекта-источника, в этом случае на выходе будет объект, сохраняющий исходную структуру первого и второго объекта
- на случай если у двух объектов есть свойства с одинаковым именем предусмотрено два варианта развития событий:
- с сохранением обоих свойств — формируется массив значений
- с заменой исходного целевым
- Ограничение глубины копирования
Ну и собственно сама функция:
/** *Функция копирования свойств одного объекта в другой * @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> максимальная глубина рекурсии(изменять с осторожностью) * @param cur_l_rec <i>int</i> текущая глубина рекурсии(не изменять) */ function objUnion(objS, objT, rec, repl, max_l_rec, cur_l_rec) { //считаем число элементов в исходном объекте var count_elem = objS.length; //если мы вернулись из глубин прибавляем к скопированным элементам единичку if(cur_l_rec == 0) { objT.summ_elem ++; } //для контроля рекурсии создадим у целевого объекта два служебных поля, //первое - глубина рекурсии, второе - количество посчитанных элементов, //дабы знать, когда достигнут конец копирования и означенные поля можно удалять if(typeof(objT.cur_l_rec) == 'undefined') { objT.cur_l_rec = 0; objT.summ_elem = 0; cur_l_rec = 0; } else { objT.cur_l_rec++; cur_l_rec++; } //если достигнут максимальный уровень рекурсии if(max_l_rec && objT.cur_l_rec == max_l_rec) { objUnion(objS, objT, rec, repl, max_l_rec, cur_l_rec); delete objT.cur_l_rec ; return; } var flag_rec = false; //начинаем копировать 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)) { flag_rec = true; objUnion(objS[key], objT, rec, repl, max_l_rec, cur_l_rec); continue; } } //определяем, что делать с полями, имеющими одинаковое имя //либо создаем из них массив, либо меняем значение первого на второе if(objT[key] && !repl) { objT[key] = [objS[key],objT[key]]; } else { objT[key] = objS[key]; } } //если скопированы свой свойства всех объектов убираем служебные поля if((objT.summ_elem == count_elem && cur_l_rec == 0) || !flag_rec) { 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, 0); //удяляем ссылку link = null; console.log(obj2);
Всех благодарю за внимание, надеюсь, мой велосипед метод будет кому-то полезен.
Автор: Slavenin999