Comment concaténer les propriétés de plusieurs objets JavaScript


105

Je recherche la meilleure façon d '"ajouter" plusieurs objets JavaScript (tableaux associatifs).

Par exemple, étant donné:

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

quelle est la meilleure façon de calculer:

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

3
Une note sémantique: malgré la syntaxe [], ce ne sont pas du tout des tableaux. L'ordre n'est pas vraiment garanti.
Álvaro González

1
L'ordre d'itération n'est pas garanti par les normes ecma. Mais c'est ainsi qu'il est implémenté dans la plupart des navigateurs. (De John Resig) Ce comportement est explicitement laissé indéfini par la spécification ECMAScript. Dans ECMA-262, section 12.6.4: La mécanique de l'énumération des propriétés ... dépend de l'implémentation. Cependant, la spécification est assez différente de l'implémentation. Toutes les implémentations modernes d'ECMAScript parcourent les propriétés d'objet dans l'ordre dans lequel elles ont été définies. Pour cette raison, l'équipe Chrome a considéré qu'il s'agissait d'un bogue et le corrigera.
Juan Mendes

Réponses:


159

ECMAscript 6 introduit Object.assign()pour y parvenir nativement en Javascript.

La méthode Object.assign () est utilisée pour copier les valeurs de toutes les propriétés propres énumérables d'un ou plusieurs objets source vers un objet cible. Il renverra l'objet cible.

Documentation MDN sur 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.assignest pris en charge dans de nombreux navigateurs modernes mais pas encore tous. Utilisez un transpilateur comme Babel et Traceur pour générer du JavaScript ES5 rétrocompatible.


4
C'est l'un des meilleurs que je puisse dire. Puisque E6 est maintenant principalement utilisé, Object.assign est la meilleure réponse.
Vimalraj Selvam

6
Si vous ne savez pas combien d'objets doivent être fusionnés, parce qu'ils sont dans un tableau, vous pouvez les fusionner comme suit:Object.assign.apply({}, [{a: 1}, {b: 2}, ....])
Jeanluca Scaljeri

1
Une alternative à l'utilisation Object.assign.applypour fusionner un tableau d'objets, consiste à utiliser à la place l'opérateur de propagation:Object.assign( ...objects )
Spen

@Spen qui est déjà inclus comme réponse à cette question. Je ne vois aucun avantage à le reproduire ici.
filoxo

après 4 heures, cette réponse a résolu mon problème dans Angular 7. Merci pour la simplicité et l'exactitude de la réponse.
Gel du

35

Vous pouvez utiliser jquery $.extendcomme ceci:

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 Même si vous n'utilisez pas la méthode de jQuery, vous pouvez utiliser leur code pour vous aider à construire votre propre implémentation (peut-être plus spécifique).
tvanfosson

25
@Randal: Il existe de nombreuses raisons parfaitement bonnes pour ne pas utiliser jQuery.
Tim Down

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

34

Cela devrait le faire:

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);

Production:

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

Ne lengthrecherche pas la taille du tableau à chaque appel? J'ai tellement l'habitude d'écrire for (var i = 0, len = array.length; i < len; ++i)que je ne me souviens pas du tout pourquoi j'ai commencé à le faire.
tvanfosson

1
Oui c'est correct. Il est préférable de mettre en cache la longueur une fois. Cependant, comme la taille des arguments "array" ne sera probablement jamais très grande, cela n'aura pas vraiment d'importance dans ce cas.
jhurshman

1
Non, sauf légèrement sur IE6. L'accès à la propriété length coûte le même prix que l'accès à la variable len.
Alsciende

1
@Juan Je pense que vous vous trompez, et j'ai fait quelques tests pour me décider. La mise en cache de la longueur est un mythe facile d'optimisation qui est obsolète depuis de nombreuses années et qui rend le code (légèrement) moins lisible. En fait, la mise en cache de la longueur ralentit parfois le navigateur (Safari).
Alsciende

2
Ne serait-il pas préférable d'écrire 'for (var p in ...' au lieu de 'for (p in ...'?
Hugo

24

ECMAScript 6 a une syntaxe étendue . Et maintenant vous pouvez faire ceci:

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

Underscore a peu de méthodes pour faire cela;

1. _.extend (destination, * sources)

Copiez toutes les propriétés des objets source dans l' objet de destination et renvoyez l' objet de destination .

_.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 (objet, * par défaut)

Remplissez les propriétés non définies dans object avec les valeurs des objets par défaut et renvoyez l' objet .

_.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

Pourquoi la fonction devrait-elle être limitée à 3 arguments? Vérifiez également 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

Le clonage superficiel (hors prototype) ou la fusion d'objets est désormais possible en utilisant une syntaxe plus courte que Object.assign () .

La syntaxe de propagation pour les littéraux d'objet a été introduite dans 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 }

L'opérateur Spread (...) est pris en charge dans de nombreux navigateurs modernes, mais pas tous.

Il est donc recommandé d'utiliser un transpilateur comme Babel pour convertir le code ECMAScript 2015+ en une version rétrocompatible de JavaScript dans les navigateurs ou environnements actuels et anciens.

Voici le code équivalent que Babel générera pour vous:

"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 }

C'est une réponse beaucoup plus robuste que la réponse acceptée. Merci!
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;
}

Remarque: les propriétés existantes dans les objets précédents seront écrasées.


2
Cela a pour effet secondaire qu'à a === dla fin. Cela pourrait être correct et non.
tvanfosson

2

Il est facile d'utiliser l' opérateur de propagation ES7 pour un objet, dans la console de votre navigateur

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

1
Agréable. Cette question a plus de 10 ans, heureux qu'une opération aussi simple soit facile maintenant. Ce n'était pas si facile avant si vous regardez les réponses des autres.
Vlad

c'est pourquoi j'ai laissé ma propre réponse :)
Purkhalo Alex

2

Pour fusionner un nombre dynamique d'objets, nous pouvons utiliser Object.assignavec la syntaxe de propagation .

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

La fonction ci-dessus accepte n'importe quel nombre d'objets, fusionnant toutes leurs propriétés dans un nouvel objet avec les propriétés des objets ultérieurs remplaçant celles des objets précédents.

Démo:

Pour fusionner un tableau d'objets, une méthode similaire peut être appliquée.

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

Démo:


1

Probablement, le moyen le plus rapide, efficace et plus générique est celui-ci (vous pouvez fusionner n'importe quel nombre d'objets et même copier dans le premier -> attribuer):

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];
}

Il vous permet également de modifier le premier objet tel qu'il est passé par référence. Si vous ne le souhaitez pas mais souhaitez avoir un objet complètement nouveau contenant toutes les propriétés, vous pouvez passer {} comme premier argument.

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); 

combiné_object et object1 contiennent tous deux les propriétés 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); 

Dans ce cas, le combine_object contient les propriétés de object1, object2, object3 mais object1 n'est pas modifié.

Vérifiez ici: https://jsfiddle.net/ppwovxey/1/

Remarque: les objets JavaScript sont passés par référence.


1

ES6 ++

La question est d'ajouter différents objets en un seul.

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

disons que vous avez un objet avec plusieurs clés qui sont des objets:

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

c'était la solution que j'ai trouvée (je dois encore foreach: /)

let objAll = {};

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

En faisant cela, nous pouvons ajouter dynamiquement TOUTES les clés d'objet en une seule.

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

0

Le plus simple: les opérateurs de diffusion

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;
}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.