Собственный способ объединения объектов в Javascript

объект Javascript не имеет собственной операции слияния. Если у вас есть два объекта, сказать

{a:1, b:2}
{c:3, d:4}

и хотите получить

{a:1, b:2, c:3, d:4}

насколько я знаю,вы должны перебирать объекты. То есть вы решаете либо объединить левую, либо объединить правую стратегию, а затем делаете что-то вроде (упрощенного)

for (key in object2) {
  object1[key] = object2[key];
}

это нормально. Однако Javascript имеет call и prototype характеристика. Например, поворот arguments в Array можно сделать

Array.prototype.slice.call(arguments)

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

вопрос

есть ли трюк, чтобы использовать этот шаблон прототипа / вызова, возможно,Attribute или Node особенности обхода DOM или, возможно, некоторые из общих String функции для выполнения слияния собственного объекта?

код будет выглядеть примерно так:

var merged = somethingrandom.obscuremethod.call(object1, object2)

и в результате вы получите собственное слияние без обхода.

возможно, оптимальным решением

если бы вы могли использовать constructor свойства Object а затем принудить один объект иметь конструктор другого объекта, а затем запустить new над составным объектом вы можете получить слияние бесплатно. Но у меня нет четкого понимания всего. последствия constructor функция в JavaScript, чтобы сделать этот звонок.

Лемма

тот же вопрос относится и к Arrays. Общая проблема заключается в том, чтобы взять, скажем, 7 массивов чисел, а затем попытаться выяснить пересечение этих массивов. То есть, какие числа существуют во всех 7 массивах.

вы могли бы соединить их вместе, затем сделать сорт, а затем сделать обход, конечно. Но было бы неплохо, если бы где-то был спрятан общий интерсект что мы можем принудить массив делать изначально.

какие мысли?

edit:

на полпути туда

для проблема выбора, вы можете сделать следующее:

массив.concat (a, b, c).род.)(присоединяйтесь (':'), а затем используйте некоторые хитрые RegExp захват и повторение шаблонов для прохождения. Реализации регулярных выражений, если вы не знаете, выполняются на очень простой виртуальной машине на основе стека. При инициализации регулярного выражения это действительно программа, которая компилируется (RegExp.compile является устаревшим методом JS). Затем туземец пробегает по струне с головокружительной скоростью. Возможно, вы могли бы использовать это для пороговых значений членства и получить лучшую производительность...

это все еще не идет до конца, хотя.

7 ответов


мой ответ на это будет обидно, но все же:

нет

причина этого проста: реализация Mr Resig слияния (или "расширения", как это называется для объектов) в jQuery делает цикл, как и в вашем вопросе. Вы можете посмотреть на него здесь. И я смею сказать, что если Джон Resig не нашел умный способ сделать это, то простые смертные stackoverflow тоже не будут:)


вопрос на миллион долларов! Я пробовал делать это многочисленными способами, и описанный выше способ петли всегда казался самым грязным. позволяет делегировать объект "переопределение свойств" объекту "свойства по умолчанию", в значительной степени выполняя то, что вы пытаетесь сделать, но используя Object.setPrototypeOf() имеет некоторые серьезные последствия, такие как отключение оптимизации компилятора браузера для всего скрипта.

кроме того, как в решении цикла, так и в Object.setPrototypeOf() решение, вы осталось с ситуацией, когда объект "переопределение свойств "может мутировать объект" свойства по умолчанию":

defaultObj = {
    a: [1, 2]
}
...
overrideObj = {
    b: 3
}
Object.setPrototypeOf(overrideObj, defaultObj);
console.log(overrideObj); // {a: [1, 2], b: 3}
// Great!
...
overrideObj.a.push(4);
console.log(defaultObj); // {a: [1, 2, 4]}
// Uh-oh.

вы можете подумать, что это не проблема, но предположим, что вы используете этот объект в качестве конфигурации для стороннего lib. Теперь вы передаете контроль над своим объектом по умолчанию и все, что в нем указано, стороннему lib.

лучшим решением может быть использование JSON.stringify и JSON.parse для копирования и объединения объектов. Вот суть с образец: https://gist.github.com/spikesagal/6f7822466887f19b9c65

HTH


насколько мне известно, нет. Кроме того, вы захотите написать свой метод слияния следующим образом:

function mergeInto(o1, o2) {
  if (o1 == null || o2 == null)
    return o1;

  for (var key in o2)
    if (o2.hasOwnProperty(key))
      o1[key] = o2[key];

  return o1;
}

используя ES6 (ES2015), вы можете использовать "объект".назначить способ:

var x = {a:1, b:2};
var y = {c:3, d:4};
var z = Object.assign({},x,y);

используя ES7 (ES2016, Chrome 60+ или Babel), вы можете использовать оператор распространения объектов:

var x = {a:1, b:2};
var y = {c:3, d:4}; 
var z = {...x, ...y};

вы можете сделать следующее, используя нативный JS 1.7, без рамок. См. пример на скрипка (пример предназначен только для простых объектов - не сложных вложенных объектов)

var obj1 = {a: "a", b: "b"};
var obj2 = {c: "c", d: "d"};

// The magic: ugly but works perfectly
var value = (JSON.stringify(obj1).concat(JSON.stringify(obj2))).replace("}{", ",");

document.getElementById("lbl1").setAttribute("value", value);

// back to object
var obj3 = JSON.parse(value);
document.getElementById("lbl2").setAttribute("value", obj3.a + " " + obj3.b + " " + obj3.c + " " + obj3.d);

нет собственных способов в ECMA-скрипте, используйте:

function merge(o1,o2) {
 if (typeof(o1)!=='object') o1={};
 if (typeof(o2)!=='object') o2={};
 for (var k in o2) {
 if (o1[k]!==undefined)
  alert ('Collision Error'); // TODO
 else
   o1[k]=o2[k];
 }
 return o1;
}

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

var merge = function(o1, o2) {
    var o_new = {};
    for(p in o1) {
        if(o1[p]) {
            if(typeof o1[p] == 'object' && !(o1[p] instanceof Array) && o2.hasOwnProperty(p)) {
                o_new[p] = merge(o1[p], o2[p]);
            }
            else {
                o_new[p] = o1[p];
            }
        }
    }
    for(p in o2) {
        if(typeof o2[p] == 'object' && !(o2[p] instanceof Array) && o1.hasOwnProperty(p)) {
            o_new[p] = merge(o1[p], o2[p]);
        }
        else {
            o_new[p] = o2[p];
        }
    }
    return o_new;
}