Родной способ слияния объектов в 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)
Этот подход использует существующий собственный код, поэтому он менее восприимчив к глупому программисту и должен работать быстрее, чем не-native-реализация.
Вопрос
Есть ли уловка для использования этого шаблона прототипа/вызова, возможно, для функций обхода Attribute
или Node
объекта DOM или, возможно, некоторых из общих String
функций, чтобы выполнить слияние собственных объектов?
Код выглядит примерно так:
var merged = somethingrandom.obscuremethod.call(object1, object2)
И в результате вы получите собственное слияние без обхода.
Возможное, субоптимальное решение
Если вы можете использовать свойство constructor
для Object
, а затем принудить один объект к созданию конструктора другого объекта, а затем запустить new
над составным объектом, вы можете получить слияние бесплатно. Но у меня нет четкого понимания всех последствий функции constructor
в javascript для выполнения этого вызова.
Лемма
Тот же вопрос справедлив для Arrays
. Общая проблема состоит в том, чтобы взять, например, 7 массивов чисел, а затем попытаться выяснить пересечение этих массивов. То есть, какие числа существуют во всех 7 массивах.
Вы могли бы объединить их вместе, затем сделать вид, а затем сделать обход, конечно. Но было бы неплохо, если бы где-то было пересечено какое-то общее пересечение, которое мы можем принудить массив к выполнению изначально.
Любые мысли?
изменить:
На полпути туда
Для проблемы с массивом вы можете сделать следующее:
array.concat(a, b, c).sort(). join (':'), а затем используйте некоторые сложные шаблоны захвата и повтора RegExp
, чтобы пройти. Реализация RegExp, если вы не знаете, запускается на очень простой виртуальной машине на основе стека. Когда вы инициализируете свое регулярное выражение, которое действительно является компиляцией программы (RegExp.compile - это устаревший метод JS). Тогда нативный пробегает строку по-быстрому. Возможно, вы можете использовать это для порогов членства и получить лучшую производительность...
Он все еще не проходит весь путь.
Ответы
Ответ 1
Мой ответ на это будет разочаровывающим, но все же:
нет не
Причина для этого проста: реализация проекта Resig слияния (или "расширение", поскольку она вызвала объекты) в jQuery делает цикл, точно такой же, как в вашем вопросе. Вы можете посмотреть здесь здесь. И я смею сказать, что если Джон Ресиг не найдет умного встроенного способа сделать это, то простые смертные из stackoverflow не будут:)
Ответ 2
Вопрос в миллион долларов! Я пробовал делать это по-разному, и описанный выше путь цикла всегда казался самым грязным. ES6 Object.setPrototypeOf()
позволяет делегировать объект переопределения свойства объекту "свойства по умолчанию", в значительной степени выполняя то, что вы пытаетесь сделать, но использование Object.setPrototypeOf()
имеет некоторые серьезные последствия, такие как отключение оптимизации компилятора браузера для весь script.
Кроме того, как в решении цикла, так и в решении 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.
Вы можете подумать, что это не проблема, но позвольте сказать, что вы используете этот объект в качестве конфигурации для сторонней библиотеки. Теперь вы передаете свой объект по умолчанию и все ссылки на него в стороннюю библиотеку.
Лучшим решением может быть использование JSON.stringify и JSON.parse для копирования и объединения объектов. Здесь Gist с примером:
https://gist.github.com/spikesagal/6f7822466887f19b9c65
НТН
Ответ 3
Не то, чтобы я знал, нет. Кроме того, вы захотите написать свой метод слияния следующим образом:
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;
}
Ответ 4
Вы можете сделать следующее, используя собственный JS 1.7, без необходимости создания фреймворка. Пример fiddle (пример предназначен только для простых объектов - не сложных вложенных объектов)
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);
Ответ 5
Используя ES6 (ES2015), вы можете использовать метод Object.assign:
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};
Ответ 6
В ECMA- Script нет собственных путей, используйте:
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;
}
Ответ 7
Вот функция, которую вы можете использовать для решения своей дилеммы.
код:
var a = {'a':'1', 'b':'2'};
var b = {'c':'3', 'd':'4'};
function appendObj(a,b) {
var aZ = 'abcdefghijklmnopqrstuvwxyz'.split('');
bKeys = Object.keys(b);
for (var i = 0; i < bKeys.length; i++) {
a[bKeys[i]] = b[bKeys[i]];
}
return a;
}
var newObj = appendObj(a,b);
console.log(newObj)
Надеюсь, это поможет.
Примечание
Я ввел это через свой телефон, поэтому прошу прощения, если есть семантические ошибки или опечатки.
Все самое лучшее,
Matt
Ответ 8
Ниже я включил функцию глубокого слияния, которую я написал. Это не приведет к глубокому объединению массивов, а только к объектам. Он примет два объекта и вернет третий, новый объект.
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;
}