Como concatenar propriedades de vários objetos JavaScript


105

Estou procurando a melhor maneira de "adicionar" vários objetos JavaScript (matrizes associativas).

Por exemplo, dado:

a = { "one" : 1, "two" : 2 };
b = { "three" : 3 };
c = { "four" : 4, "five" : 5 };

qual é a melhor maneira de calcular:

{ "one" : 1, "two" : 2, "three" : 3, "four" : 4, "five" : 5 }

3
Uma nota semântica: apesar da sintaxe [], eles não são arrays. A ordem não é realmente garantida.
— Álvaro González

1
A ordem de iteração não é garantida pelos padrões da ecma. Mas é a forma como é implementado na maioria dos navegadores. (De John Resig) Este comportamento é explicitamente deixado indefinido pela especificação ECMAScript. Na ECMA-262, seção 12.6.4: A mecânica de enumerar as propriedades ... depende da implementação. No entanto, a especificação é bastante diferente da implementação. Todas as implementações modernas do ECMAScript iteram por meio das propriedades do objeto na ordem em que foram definidas. Por causa disso, a equipe do Chrome considerou isso um bug e irá corrigi-lo.
— Juan Mendes,

Respostas:


159

ECMAscript 6 introduzido Object.assign()para conseguir isso nativamente em Javascript.

O método Object.assign () é usado para copiar os valores de todas as propriedades próprias enumeráveis ​​de um ou mais objetos de origem para um objeto de destino. Ele retornará o objeto de destino.

Documentação MDN em Object.assign ()

var o1 = { a: 1 };
var o2 = { b: 2 };
var o3 = { c: 3 };

var obj = Object.assign({}, o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3 }

Object.assigné suportado em muitos navegadores modernos, mas ainda não em todos. Use um transpiler como Babel e Traceur para gerar JavaScript ES5 compatível com versões anteriores.


4
Este é um dos melhores que eu poderia dizer. Como E6 agora é mais usado, Object.assign é a melhor resposta.
— Vimalraj Selvam

6
Se você não sabe quantos objetos precisam ser mesclados, porque eles estão em uma matriz, você pode mesclá-los da seguinte forma:Object.assign.apply({}, [{a: 1}, {b: 2}, ....])
— Jeanluca Scaljeri

1
Uma alternativa ao uso Object.assign.applypara mesclar uma matriz de objetos é usar o operador de propagação:Object.assign( ...objects )
— Spen

@Spen que já está incluído como resposta a esta pergunta. Não vi benefício em duplicá-lo aqui.
— filoxo

após 4 horas, esta resposta resolveu meu problema no Angular 7. Obrigado pela simplicidade e precisão da resposta.
— Gel de

35

Você pode usar o jquery $.extendassim:

let a = { "one" : 1, "two" : 2 },
    b = { "three" : 3 },
    c = { "four" : 4, "five" : 5 };

let d = $.extend({}, a, b, c)

console.log(d)
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>


1 Mesmo se você não usar o método jQuery, você pode usar o código deles para ajudar a construir sua própria (talvez, mais específica) implementação.
— tvanfosson

25
@Randal: Existem muitas razões perfeitamente boas para não usar o jQuery.
— Tim Down,

3
Editar:d = $.extend({},a,b,c);
— Bob Stein

34

Isso deve servir:

function collect() {
  var ret = {};
  var len = arguments.length;
  for (var i = 0; i < len; i++) {
    for (p in arguments[i]) {
      if (arguments[i].hasOwnProperty(p)) {
        ret[p] = arguments[i][p];
      }
    }
  }
  return ret;
}

let a = { "one" : 1, "two" : 2 };
let b = { "three" : 3 };
let c = { "four" : 4, "five" : 5 };

let d = collect(a, b, c);
console.log(d);

Resultado:

{
  "one": 1,
  "two": 2,
  "three": 3,
  "four": 4,
  "five": 5
}

Não lengthpesquisa o tamanho da matriz em cada invocação? Estou tão acostumada a escrever for (var i = 0, len = array.length; i < len; ++i)que não consigo lembrar de cara por que comecei a fazer isso.
— tvanfosson

1
Sim esta correto. É melhor desempenho armazenar em cache o comprimento uma vez. No entanto, como o tamanho dos argumentos "array" provavelmente não será muito grande, isso realmente não importará neste caso.
— jhurshman

1
Não, exceto ligeiramente no IE6. Acessar a propriedade length custa o mesmo que acessar a variável len.
— Alsciende

1
@ Juan Eu acredito que você está errado, e fiz alguns testes para me decidir. Armazenar o tamanho do cache é um mito fácil de otimização que está obsoleto há muitos anos e torna o código (ligeiramente) menos legível. Na verdade, o armazenamento em cache às vezes torna o navegador mais lento (Safari).
— Alsciende

2
Não seria melhor escrever "para (var p em ..." em vez de "para (p em ..."?
— Hugo

24

ECMAScript 6 espalhou sintaxe . E agora você pode fazer isso:

const obj1 = { 1: 11, 2: 22 };
const obj2 = { 3: 33, 4: 44 };
const obj3 = { ...obj1, ...obj2 };

console.log(obj3); // {1: 11, 2: 22, 3: 33, 4: 44}


12

O sublinhado tem poucos métodos para fazer isso;

1. _.extend (destino, * fontes)

Copie todas as propriedades dos objetos de origem para o objeto de destino e retorne o objeto de destino .

_.extend(a, _.extend(b, c));
=> {"one" : 1, "two" : 2, "three" : 3, "four" : 4, "five" : 5 }

Ou

_.extend(a, b);
=> {"one" : 1, "two" : 2, "three" : 3}
_.extend(a, c);
=> {"one" : 1, "two" : 2, "three" : 3, "four" : 4, "five" : 5 }

2. _.defaults (objeto, * padrões)

Preencha as propriedades indefinidas no objeto com valores dos objetos padrão e retorne o objeto .

_.defaults(a, _.defaults(b, c));
=> {"one" : 1, "two" : 2, "three" : 3, "four" : 4, "five" : 5 }

Ou

_.defaults(a, b);
=> {"one" : 1, "two" : 2, "three" : 3}
_.defaults(a, c);
=> {"one" : 1, "two" : 2, "three" : 3, "four" : 4, "five" : 5 }

4

Por que a função deve ser restrita a 3 argumentos? Além disso, verifique hasOwnProperty.

function Collect() {
    var o={};
    for(var i=0;i<arguments.length;i++) {
      var arg=arguments[i];
      if(typeof arg != "object") continue;
      for(var p in arg) {
        if(arg.hasOwnProperty(p)) o[p] = arg[p];
      }
    }
    return o;
}

4

A clonagem superficial (excluindo protótipo) ou mesclagem de objetos agora é possível usando uma sintaxe mais curta do que Object.assign () .

A sintaxe de propagação para literais de objeto foi introduzida no ECMAScript 2018 ):

const a = { "one": 1, "two": 2 };
const b = { "three": 3 };
const c = { "four": 4, "five": 5 };

const result = {...a, ...b, ...c};
// Object { "one": 1, "two": 2 , "three": 3, "four": 4, "five": 5 }

O operador Spread (...) é suportado em muitos navegadores modernos, mas não em todos.

Portanto, é recomendável usar um transpiler como o Babel para converter o código ECMAScript 2015+ em uma versão compatível com versões anteriores de JavaScript em navegadores ou ambientes atuais e mais antigos.

Este é o código equivalente que o Babel irá gerar para você:

"use strict";

var _extends = Object.assign || function(target) {
  for (var i = 1; i < arguments.length; i++) {
    var source = arguments[i];
    for (var key in source) {
      if (Object.prototype.hasOwnProperty.call(source, key)) {
        target[key] = source[key];
      }
    }
  }
  return target;
};

var a = { "one": 1, "two": 2 };
var b = { "three": 3 };
var c = { "four": 4, "five": 5 };

var result = _extends({}, a, b, c);
// Object { "one": 1, "two": 2 , "three": 3, "four": 4, "five": 5 }

Esta é uma resposta muito mais robusta do que a resposta aceita. Obrigado!
— Kaleb Anderson

3
function Collect(a, b, c) {
    for (property in b)
        a[property] = b[property];

    for (property in c)
        a[property] = c[property];

    return a;
}

Aviso: as propriedades existentes nos objetos anteriores serão sobrescritas.


2
Isso tem o efeito colateral que a === dno final. Isso pode estar ok ou não.
— tvanfosson

2

É fácil usar o operador spread ES7 para um objeto, no console do seu navegador, coloque

({ name: "Alex", ...(true  ? { age: 19 } : { })}) // {name: "Alex", age: 19}
({ name: "Alex", ...(false ? { age: 19 } : { })}) // {name: "Alex",        }

1
Agradável. Esta pergunta tem mais de 10 anos, feliz que uma operação tão simples seja fácil agora. Não era tão fácil antes, se você olhar para as respostas das outras pessoas.
— Vlad

é por isso que deixei minha própria resposta :)
— Purkhalo Alex

2

Para mesclar um número dinâmico de objetos, podemos usar Object.assigncom sintaxe de propagação .

const mergeObjs = (...objs) => Object.assign({}, ...objs);

A função acima aceita qualquer número de objetos, mesclando todas as suas propriedades em um novo objeto com propriedades de objetos posteriores sobrescrevendo aquelas de objetos anteriores.

Demo:

Para mesclar uma matriz de objetos, um método semelhante pode ser aplicado.

const mergeArrayOfObjs = arr => Object.assign({}, ...arr);

Demo:


1

Provavelmente, a maneira mais rápida, eficiente e genérica é esta (você pode mesclar qualquer número de objetos e até mesmo copiar para o primeiro -> atribuir):

function object_merge(){
    for (var i=1; i<arguments.length; i++)
       for (var a in arguments[i])
         arguments[0][a] = arguments[i][a];
   return arguments[0];
}

Ele também permite que você modifique o primeiro objeto conforme ele passa por referência. Se você não deseja isso, mas deseja um objeto completamente novo contendo todas as propriedades, você pode passar {} como o primeiro argumento.

var object1={a:1,b:2};
var object2={c:3,d:4};
var object3={d:5,e:6};
var combined_object=object_merge(object1,object2,object3); 

combinado_object e object1 contêm as propriedades de object1, object2, object3.

var object1={a:1,b:2};
var object2={c:3,d:4};
var object3={d:5,e:6};
var combined_object=object_merge({},object1,object2,object3); 

Nesse caso, o combinado_objeto contém as propriedades de objeto1, objeto2, objeto3, mas objeto1 não é modificado.

Verifique aqui: https://jsfiddle.net/ppwovxey/1/

Nota: os objetos JavaScript são passados ​​por referência.


1

ES6 ++

A questão é adicionar vários objetos diferentes em um.

let obj = {};
const obj1 = { foo: 'bar' };
const obj2 = { bar: 'foo' };
Object.assign(obj, obj1, obj2);
//output => {foo: 'bar', bar: 'foo'};

digamos que você tenha um objeto com várias chaves que são objetos:

let obj = {
  foo: { bar: 'foo' },
  bar: { foo: 'bar' }
}

esta foi a solução que encontrei (ainda tenho que foreach: /)

let objAll = {};

Object.values(obj).forEach(o => {
  objAll = {...objAll, ...o};
});

Fazendo isso, podemos adicionar dinamicamente TODAS as chaves de objeto em uma.

// Output => { bar: 'foo', foo: 'bar' }

0

Mais simples: espalhar operadores

var obj1 = {a: 1}
var obj2 = {b: 2}
var concat = { ...obj1, ...obj2 } // { a: 1, b: 2 }

-2
function collect(a, b, c){
    var d = {};

    for(p in a){
        d[p] = a[p];
    }
    for(p in b){
        d[p] = b[p];
    }
    for(p in c){
        d[p] = c[p];
    }

    return d;
}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.