Je dois pouvoir fusionner deux objets JavaScript (très simples) au moment de l'exécution. Par exemple, j'aimerais:
var obj1 = { food: 'pizza', car: 'ford' }
var obj2 = { animal: 'dog' }
obj1.merge(obj2);
//obj1 now has three properties: food, car, and animal
Quelqu'un a-t-il un script pour cela ou connaît-il une méthode intégrée pour le faire? Je n'ai pas besoin de récursion ni de fusion de fonctions, mais simplement de méthodes sur des objets plats.
Méthode standard ECMAScript 2018
Vous utiliseriez object spread :
let merged = {...obj1, ...obj2};
/** There's no limit to the number of objects you can merge.
* Later properties overwrite earlier properties with the same name. */
const allRules = {...obj1, ...obj2, ...obj3};
Méthode standard ECMAScript 2015 (ES6)
/* For the case in question, you would do: */
Object.assign(obj1, obj2);
/** There's no limit to the number of objects you can merge.
* All objects get merged into the first object.
* Only the object in the first argument is mutated and returned.
* Later properties overwrite earlier properties with the same name. */
const allRules = Object.assign({}, obj1, obj2, obj3, etc);
(voir Référence JavaScript MDN )
Méthode pour ES5 et versions antérieures
for (var attrname in obj2) { obj1[attrname] = obj2[attrname]; }
Notez que ceci ajoutera simplement tous les attributs de obj2
à obj1
, ce qui pourrait ne pas être ce que vous souhaitez si vous souhaitez toujours utiliser le obj1
non modifié.
Si vous utilisez un framework qui craint sur tous vos prototypes, vous devez utiliser des contrôles plus sophistiqués comme hasOwnProperty
, mais ce code fonctionnera dans 99% des cas.
Exemple de fonction:
/**
* Overwrites obj1's values with obj2's and adds obj2's if non existent in obj1
* @param obj1
* @param obj2
* @returns obj3 a new object based on obj1 and obj2
*/
function merge_options(obj1,obj2){
var obj3 = {};
for (var attrname in obj1) { obj3[attrname] = obj1[attrname]; }
for (var attrname in obj2) { obj3[attrname] = obj2[attrname]; }
return obj3;
}
jQuery a également un utilitaire pour cela: http://api.jquery.com/jQuery.extend/ .
Extrait de la documentation jQuery:
// Merge options object into settings object
var settings = { validate: false, limit: 5, name: "foo" };
var options = { validate: true, name: "bar" };
jQuery.extend(settings, options);
// Now the content of settings object is the following:
// { validate: true, limit: 5, name: "bar" }
Le code ci-dessus mue l'objet existant nommé settings
.
Si vous voulez créer un objet new sans modifier aucun des arguments, utilisez ceci:
var defaults = { validate: false, limit: 5, name: "foo" };
var options = { validate: true, name: "bar" };
/* Merge defaults and options, without modifying defaults */
var settings = $.extend({}, defaults, options);
// The content of settings variable is now the following:
// {validate: true, limit: 5, name: "bar"}
// The 'defaults' and 'options' variables remained the same.
Le Harmony ECMAScript 2015 (ES6) spécifie Object.assign
qui le fera.
Object.assign(obj1, obj2);
Le support actuel du navigateur est améliore , mais si vous développez pour des navigateurs sans support, vous pouvez utiliser un polyfill .
J'ai cherché sur Google pour que le code fusionne les propriétés de l'objet et je me suis retrouvé ici. Cependant, puisqu'il n'y avait pas de code pour la fusion récursive, je l'ai écrit moi-même. (Peut-être que l'extension de jQuery est récursive BTW?) Quoi qu'il en soit, j'espère que quelqu'un le trouvera utile également.
(Maintenant, le code n'utilise pas Object.prototype
:)
/*
* Recursively merge properties of two objects
*/
function MergeRecursive(obj1, obj2) {
for (var p in obj2) {
try {
// Property in destination object set; update its value.
if ( obj2[p].constructor==Object ) {
obj1[p] = MergeRecursive(obj1[p], obj2[p]);
} else {
obj1[p] = obj2[p];
}
} catch(e) {
// Property in destination object not set; create it and set its value.
obj1[p] = obj2[p];
}
}
return obj1;
}
o1 = { a : 1,
b : 2,
c : {
ca : 1,
cb : 2,
cc : {
cca : 100,
ccb : 200 } } };
o2 = { a : 10,
c : {
ca : 10,
cb : 20,
cc : {
cca : 101,
ccb : 202 } } };
o3 = MergeRecursive(o1, o2);
Produit un objet o3 comme
o3 = { a : 10,
b : 2,
c : {
ca : 10,
cb : 20,
cc : {
cca : 101,
ccb : 202 } } };
Notez que underscore.js
's extend
- method fait ceci dans une ligne:
_.extend({name : 'moe'}, {age : 50});
=> {name : 'moe', age : 50}
Semblable à jQuery extend (), vous avez la même fonction dans AngularJS :
// Merge the 'options' object into the 'settings' object
var settings = {validate: false, limit: 5, name: "foo"};
var options = {validate: true, name: "bar"};
angular.extend(settings, options);
J'ai besoin de fusionner des objets aujourd'hui, et cette question (et ces réponses) m'ont beaucoup aidé. J'ai essayé certaines des réponses, mais aucune d'entre elles ne correspondait à mes besoins. J'ai donc combiné certaines des réponses, ajouté quelque chose et créé une nouvelle fonction de fusion. C'est ici:
var merge = function() {
var obj = {},
i = 0,
il = arguments.length,
key;
for (; i < il; i++) {
for (key in arguments[i]) {
if (arguments[i].hasOwnProperty(key)) {
obj[key] = arguments[i][key];
}
}
}
return obj;
};
Quelques exemples d'utilisations:
var t1 = {
key1: 1,
key2: "test",
key3: [5, 2, 76, 21]
};
var t2 = {
key1: {
ik1: "hello",
ik2: "world",
ik3: 3
}
};
var t3 = {
key2: 3,
key3: {
t1: 1,
t2: 2,
t3: {
a1: 1,
a2: 3,
a4: [21, 3, 42, "asd"]
}
}
};
console.log(merge(t1, t2));
console.log(merge(t1, t3));
console.log(merge(t2, t3));
console.log(merge(t1, t2, t3));
console.log(merge({}, t1, { key1: 1 }));
Vous pouvez utiliser propriétés de propagation d'objet - actuellement une proposition ECMAScript d'étape 3.
const obj1 = { food: 'pizza', car: 'ford' };
const obj2 = { animal: 'dog' };
const obj3 = { ...obj1, ...obj2 };
console.log(obj3);
Les solutions données doivent être modifiées pour vérifier source.hasOwnProperty(property)
dans les boucles for..in
avant d'attribuer - sinon, vous finissez par copier les propriétés de la chaîne de prototypes complète, ce qui est rarement souhaité ...
Une méthode Object.assign
fait partie de la norme ECMAScript 2015 (ES6) et fait exactement ce dont vous avez besoin. (IE
non pris en charge)
var clone = Object.assign({}, obj);
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.
Polyfill pour prendre en charge les anciens navigateurs:
if (!Object.assign) {
Object.defineProperty(Object, 'assign', {
enumerable: false,
configurable: true,
writable: true,
value: function(target) {
'use strict';
if (target === undefined || target === null) {
throw new TypeError('Cannot convert first argument to object');
}
var to = Object(target);
for (var i = 1; i < arguments.length; i++) {
var nextSource = arguments[i];
if (nextSource === undefined || nextSource === null) {
continue;
}
nextSource = Object(nextSource);
var keysArray = Object.keys(nextSource);
for (var nextIndex = 0, len = keysArray.length; nextIndex < len; nextIndex++) {
var nextKey = keysArray[nextIndex];
var desc = Object.getOwnPropertyDescriptor(nextSource, nextKey);
if (desc !== undefined && desc.enumerable) {
to[nextKey] = nextSource[nextKey];
}
}
}
return to;
}
});
}
Les deux suivants sont probablement un bon point de départ. Lodash a également une fonction de personnalisation pour ces besoins spéciaux!
_.extend
( http://underscorejs.org/#extend ) _.merge
( https://lodash.com/docs#merge )
En passant, ce que vous faites tous, c’est écraser les propriétés, pas les fusionner ...
C’est ainsi que la zone des objets JavaScript a vraiment fusionné: Seules les clés de l’objet to
qui ne sont pas des objets eux-mêmes seront remplacées par from
. Tout le reste seravraiment fusionné. Bien sûr, vous pouvez changer ce comportement pour ne pas écraser quoi que ce soit qui existe comme si seulement to[n] is undefined
, etc ...:
var realMerge = function (to, from) {
for (n in from) {
if (typeof to[n] != 'object') {
to[n] = from[n];
} else if (typeof from[n] == 'object') {
to[n] = realMerge(to[n], from[n]);
}
}
return to;
};
Usage:
var merged = realMerge(obj1, obj2);
Voici mon coup de couteau qui
C'est court :)
/*
Recursively merge properties and return new object
obj1 <- obj2 [ <- ... ]
*/
function merge () {
var dst = {}
,src
,p
,args = [].splice.call(arguments, 0)
;
while (args.length > 0) {
src = args.splice(0, 1)[0];
if (toString.call(src) == '[object Object]') {
for (p in src) {
if (src.hasOwnProperty(p)) {
if (toString.call(src[p]) == '[object Object]') {
dst[p] = merge(dst[p] || {}, src[p]);
} else {
dst[p] = src[p];
}
}
}
}
}
return dst;
}
Exemple:
a = {
"p1": "p1a",
"p2": [
"a",
"b",
"c"
],
"p3": true,
"p5": null,
"p6": {
"p61": "p61a",
"p62": "p62a",
"p63": [
"aa",
"bb",
"cc"
],
"p64": {
"p641": "p641a"
}
}
};
b = {
"p1": "p1b",
"p2": [
"d",
"e",
"f"
],
"p3": false,
"p4": true,
"p6": {
"p61": "p61b",
"p64": {
"p642": "p642b"
}
}
};
c = {
"p1": "p1c",
"p3": null,
"p6": {
"p62": "p62c",
"p64": {
"p643": "p641c"
}
}
};
d = merge(a, b, c);
/*
d = {
"p1": "p1c",
"p2": [
"d",
"e",
"f"
],
"p3": null,
"p5": null,
"p6": {
"p61": "p61b",
"p62": "p62c",
"p63": [
"aa",
"bb",
"cc"
],
"p64": {
"p641": "p641a",
"p642": "p642b",
"p643": "p641c"
}
},
"p4": true
};
*/
Object.assign ()
ECMAScript 2015 (ES6)
Il s'agit d'une nouvelle technologie qui fait partie de la norme ECMAScript 2015 (ES6) . Les spécifications de cette technologie ont été finalisées, mais vérifiez le tableau de compatibilité pour connaître l'état d'utilisation et de mise en œuvre dans les différents navigateurs.
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 retournera l'objet cible.
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 }
console.log(o1); // { a: 1, b: 2, c: 3 }, target object itself is changed.
Pour les objets pas trop compliqués, vous pouvez utiliser JSON :
var obj1 = { food: 'pizza', car: 'ford' }
var obj2 = { animal: 'dog', car: 'chevy'}
var objMerge;
objMerge = JSON.stringify(obj1) + JSON.stringify(obj2);
// {"food": "pizza","car":"ford"}{"animal":"dog","car":"chevy"}
objMerge = objMerge.replace(/\}\{/, ","); // \_ replace with comma for valid JSON
objMerge = JSON.parse(objMerge); // { food: 'pizza', animal: 'dog', car: 'chevy'}
// Of same keys in both objects, the last object's value is retained_/
Notez que dans cet exemple "} {" ne doit pas se produire dans une chaîne!
Pour ce faire, la meilleure solution consiste à ajouter une propriété appropriée non énumérable à l'aide de Object.defineProperty.
De cette façon, vous pourrez toujours parcourir les propriétés de vos objets sans avoir la "extension" créée que vous obtiendriez si vous créiez la propriété avec Object.prototype.extend.
Espérons que cela aide:
Object.defineProperty (Object.prototype, "extend", { Enumerable: false, Value: function (from) { Var props = Object.getOwnPropertyNames (from); .__ var dest = this; props.forEach (fonction (nom) { if (nom dans dest) { var destination = Object.getOwnPropertyDescriptor (from, name); Object.defineProperty (dest, nom, destination); } }); renvoyer ceci; } });
Une fois que cela fonctionne, vous pouvez faire:
var obj = { nom: 'pile', finish: 'overflow' } var replacement = { nom: 'stock' }; obj.extend (remplacement);
Je viens d'écrire un billet de blog à ce sujet ici: http://onemoredigit.com/post/1527191998/extending-objects-in-node-js
Vous pouvez simplement utiliser jQueryextend
var obj1 = { val1: false, limit: 5, name: "foo" };
var obj2 = { val2: true, name: "bar" };
jQuery.extend(obj1, obj2);
Maintenant, obj1
contient toutes les valeurs de obj1
et obj2
Prototype a ceci:
Object.extend = function(destination,source) {
for (var property in source)
destination[property] = source[property];
return destination;
}
obj1.extend(obj2)
fera ce que vous voulez.
Juste si quelqu'un utilise Bibliothèque Google Closure :
goog.require('goog.object');
var a = {'a': 1, 'b': 2};
var b = {'b': 3, 'c': 4};
goog.object.extend(a, b);
// Now object a == {'a': 1, 'b': 3, 'c': 4};
Une fonction d'assistance similaire existe pour array :
var a = [1, 2];
var b = [3, 4];
goog.array.extend(a, b); // Extends array 'a'
goog.array.concat(a, b); // Returns concatenation of array 'a' and 'b'
J'ai étendu la méthode de David Coallier:
Si override est défini sur false, aucune propriété n'est remplacée, mais de nouvelles propriétés sont ajoutées.
Utilisation: Obj.merge (merges ... [ override]);
Voici mon code:
Object.defineProperty(Object.prototype, "merge", {
enumerable: false,
value: function () {
var override = true,
dest = this,
len = arguments.length,
props, merge, i, from;
if (typeof(arguments[arguments.length - 1]) === "boolean") {
override = arguments[arguments.length - 1];
len = arguments.length - 1;
}
for (i = 0; i < len; i++) {
from = arguments[i];
if (from != null) {
Object.getOwnPropertyNames(from).forEach(function (name) {
var descriptor;
// nesting
if ((typeof(dest[name]) === "object" || typeof(dest[name]) === "undefined")
&& typeof(from[name]) === "object") {
// ensure proper types (Array rsp Object)
if (typeof(dest[name]) === "undefined") {
dest[name] = Array.isArray(from[name]) ? [] : {};
}
if (override) {
if (!Array.isArray(dest[name]) && Array.isArray(from[name])) {
dest[name] = [];
}
else if (Array.isArray(dest[name]) && !Array.isArray(from[name])) {
dest[name] = {};
}
}
dest[name].merge(from[name], override);
}
// flat properties
else if ((name in dest && override) || !(name in dest)) {
descriptor = Object.getOwnPropertyDescriptor(from, name);
if (descriptor.configurable) {
Object.defineProperty(dest, name, descriptor);
}
}
});
}
}
return this;
}
});
Exemples et cas de test:
function clone (obj) {
return JSON.parse(JSON.stringify(obj));
}
var obj = {
name : "trick",
value : "value"
};
var mergeObj = {
name : "truck",
value2 : "value2"
};
var mergeObj2 = {
name : "track",
value : "mergeObj2",
value2 : "value2-mergeObj2",
value3 : "value3"
};
assertTrue("Standard", clone(obj).merge(mergeObj).equals({
name : "truck",
value : "value",
value2 : "value2"
}));
assertTrue("Standard no Override", clone(obj).merge(mergeObj, false).equals({
name : "trick",
value : "value",
value2 : "value2"
}));
assertTrue("Multiple", clone(obj).merge(mergeObj, mergeObj2).equals({
name : "track",
value : "mergeObj2",
value2 : "value2-mergeObj2",
value3 : "value3"
}));
assertTrue("Multiple no Override", clone(obj).merge(mergeObj, mergeObj2, false).equals({
name : "trick",
value : "value",
value2 : "value2",
value3 : "value3"
}));
var deep = {
first : {
name : "trick",
val : "value"
},
second : {
foo : "bar"
}
};
var deepMerge = {
first : {
name : "track",
anotherVal : "wohoo"
},
second : {
foo : "baz",
bar : "bam"
},
v : "on first layer"
};
assertTrue("Deep merges", clone(deep).merge(deepMerge).equals({
first : {
name : "track",
val : "value",
anotherVal : "wohoo"
},
second : {
foo : "baz",
bar : "bam"
},
v : "on first layer"
}));
assertTrue("Deep merges no override", clone(deep).merge(deepMerge, false).equals({
first : {
name : "trick",
val : "value",
anotherVal : "wohoo"
},
second : {
foo : "bar",
bar : "bam"
},
v : "on first layer"
}));
var obj1 = {a: 1, b: "hello"};
obj1.merge({c: 3});
assertTrue(obj1.equals({a: 1, b: "hello", c: 3}));
obj1.merge({a: 2, b: "mom", d: "new property"}, false);
assertTrue(obj1.equals({a: 1, b: "hello", c: 3, d: "new property"}));
var obj2 = {};
obj2.merge({a: 1}, {b: 2}, {a: 3});
assertTrue(obj2.equals({a: 3, b: 2}));
var a = [];
var b = [1, [2, 3], 4];
a.merge(b);
assertEquals(1, a[0]);
assertEquals([2, 3], a[1]);
assertEquals(4, a[2]);
var o1 = {};
var o2 = {a: 1, b: {c: 2}};
var o3 = {d: 3};
o1.merge(o2, o3);
assertTrue(o1.equals({a: 1, b: {c: 2}, d: 3}));
o1.b.c = 99;
assertTrue(o2.equals({a: 1, b: {c: 2}}));
// checking types with arrays and objects
var bo;
a = [];
bo = [1, {0:2, 1:3}, 4];
b = [1, [2, 3], 4];
a.merge(b);
assertTrue("Array stays Array?", Array.isArray(a[1]));
a = [];
a.merge(bo);
assertTrue("Object stays Object?", !Array.isArray(a[1]));
a = [];
a.merge(b);
a.merge(bo);
assertTrue("Object overrides Array", !Array.isArray(a[1]));
a = [];
a.merge(b);
a.merge(bo, false);
assertTrue("Object does not override Array", Array.isArray(a[1]));
a = [];
a.merge(bo);
a.merge(b);
assertTrue("Array overrides Object", Array.isArray(a[1]));
a = [];
a.merge(bo);
a.merge(b, false);
assertTrue("Array does not override Object", !Array.isArray(a[1]));
Ma méthode equals peut être trouvée ici: Comparaison d'objets en JavaScript
Dans MooTools , il y a Object.merge () :
Object.merge(obj1, obj2);
La fusion d'objets est simple.
var obj1 = { food: 'pizza', car: 'ford' }
var obj2 = { animal: 'dog', car: 'BMW' }
var obj3 = {a: "A"}
var mergedObj = Object.assign(obj1,obj2,obj3)
console.log(mergedObj);
Les objets sont fusionnés de droite à gauche, ce qui signifie que les objets ayant des propriétés identiques à celles de droite seront remplacés.
Dans cet exemple, obj2.car
remplace obj1.car
Dans Ext JS 4, procédez comme suit:
var mergedObject = Ext.Object.merge(object1, object2)
// Or shorter:
var mergedObject2 = Ext.merge(object1, object2)
Voir merge (object): Object.
Basé sur Markus ' et vsync' answer , il s'agit d'une version développée. La fonction prend un nombre quelconque d'arguments. Il peut être utilisé pour définir des propriétés sur DOM nœuds et crée des copies complètes de valeurs. Cependant, le premier argument est donné par référence.
Pour détecter un nœud DOM, la fonction isDOMNode () est utilisée (voir Question relative au débordement de pile JavaScript isDOM - Comment vérifier si un objet JavaScript est un objet DOM?)
Il a été testé dans Opera 11, Firefox 6, Internet Explorer 8 et Google Chrome 16.
function mergeRecursive() {
// _mergeRecursive does the actual job with two arguments.
var _mergeRecursive = function (dst, src) {
if (isDOMNode(src) || typeof src !== 'object' || src === null) {
return dst;
}
for (var p in src) {
if (!src.hasOwnProperty(p))
continue;
if (src[p] === undefined)
continue;
if ( typeof src[p] !== 'object' || src[p] === null) {
dst[p] = src[p];
} else if (typeof dst[p]!=='object' || dst[p] === null) {
dst[p] = _mergeRecursive(src[p].constructor===Array ? [] : {}, src[p]);
} else {
_mergeRecursive(dst[p], src[p]);
}
}
return dst;
}
// Loop through arguments and merge them into the first argument.
var out = arguments[0];
if (typeof out !== 'object' || out === null)
return out;
for (var i = 1, il = arguments.length; i < il; i++) {
_mergeRecursive(out, arguments[i]);
}
return out;
}
Définir innerHTML et le style d'un élément HTML
mergeRecursive(
document.getElementById('mydiv'),
{style: {border: '5px solid green', color: 'red'}},
{innerHTML: 'Hello world!'});
Fusionner des tableaux et des objets. Notez que indéfini peut être utilisé pour conserver les valeurs dans le tableau/objet de gauche.
o = mergeRecursive({a:'a'}, [1,2,3], [undefined, null, [30,31]], {a:undefined, b:'b'});
// o = {0:1, 1:null, 2:[30,31], a:'a', b:'b'}
Tout argument ne constituant pas un objet JavaScript (y compris null) sera ignoré. À l'exception du premier argument, les nœuds DOM sont également ignorés. Attention, les chaînes créées comme les nouveaux String () sont en fait des objets.
o = mergeRecursive({a:'a'}, 1, true, null, undefined, [1,2,3], 'bc', new String('de'));
// o = {0:'d', 1:'e', 2:3, a:'a'}
Si vous souhaitez fusionner deux objets dans un nouvel (sans affecter aucun des deux), fournissez {} comme premier argument.
var a={}, b={b:'abc'}, c={c:'cde'}, o;
o = mergeRecursive(a, b, c);
// o===a is true, o===b is false, o===c is false
Edit (par ReaperSoon):
Pour fusionner également des tableaux
function mergeRecursive(obj1, obj2) {
if (Array.isArray(obj2)) { return obj1.concat(obj2); }
for (var p in obj2) {
try {
// Property in destination object set; update its value.
if ( obj2[p].constructor==Object ) {
obj1[p] = mergeRecursive(obj1[p], obj2[p]);
} else if (Array.isArray(obj2[p])) {
obj1[p] = obj1[p].concat(obj2[p]);
} else {
obj1[p] = obj2[p];
}
} catch(e) {
// Property in destination object not set; create it and set its value.
obj1[p] = obj2[p];
}
}
return obj1;
}
Wow .. c'est le premier article StackOverflow que j'ai vu avec plusieurs pages. Toutes mes excuses pour l'ajout d'une autre "réponse"
Cette méthode est pour ES5 et versions antérieures - il existe de nombreuses autres réponses concernant ES6.
Je n'ai vu aucun objet "deep" _ fusionner à l'aide de la propriété arguments
. Voici ma réponse - compact & recursive, autorisant la transmission d'arguments d'objet illimités:
function extend() {
for (var o = {}, i = 0; i < arguments.length; i++) {
// if (arguments[i].constructor !== Object) continue;
for (var k in arguments[i]) {
if (arguments[i].hasOwnProperty(k)) {
o[k] = arguments[i][k].constructor === Object ? extend(o[k] || {}, arguments[i][k]) : arguments[i][k];
}
}
}
return o;
}
La partie commentée est facultative .. elle ignorera simplement les arguments passés qui ne sont pas des objets (prévention des erreurs).
Exemple:
extend({
api: 1,
params: {
query: 'hello'
}
}, {
params: {
query: 'there'
}
});
// outputs {api: 1, params: {query: 'there'}}
_ {Cette réponse n'est plus qu'une goutte d'eau dans l'océan ...} _
Avec Underscore.js , pour fusionner un tableau d'objets:
var arrayOfObjects = [ {a:1}, {b:2, c:3}, {d:4} ];
_(arrayOfObjects).reduce(function(memo, o) { return _(memo).extend(o); });
Il en résulte:
Object {a: 1, b: 2, c: 3, d: 4}
Il est à noter que la version de la collection 140byt.es résout la tâche dans un espace minimum et vaut la peine d'être essayée à cette fin:
Code:
function m(a,b,c){for(c in b)b.hasOwnProperty(c)&&((typeof a[c])[0]=='o'?m(a[c],b[c]):a[c]=b[c])}
Utilisation pour votre but:
m(obj1,obj2);
Voici le original Gist .
Vous devriez utiliser defaultsDeep de lodash
_.defaultsDeep({ 'user': { 'name': 'barney' } }, { 'user': { 'name': 'fred', 'age': 36 } });
// → { 'user': { 'name': 'barney', 'age': 36 } }
J'utilise ce qui suit qui est en JavaScript pur. Il commence à partir de l'argument le plus à droite et les combine jusqu'au dernier argument. Il n'y a pas de valeur de retour, seul le premier argument est modifié et le paramètre le plus à gauche (sauf le premier) a le poids le plus élevé pour les propriétés.
var merge = function() {
var il = arguments.length;
for (var i = il - 1; i > 0; --i) {
for (var key in arguments[i]) {
if (arguments[i].hasOwnProperty(key)) {
arguments[0][key] = arguments[i][key];
}
}
}
};
var obj1 = { food: 'pizza', car: 'ford' }
var obj2 = { animal: 'dog' }
// result
result: {food: "pizza", car: "ford", animal: "dog"}
Utilisation de jQuery.extend () - Link
// Merge obj1 & obj2 to result
var result1 = $.extend( {}, obj1, obj2 );
Utiliser _.merge () - Link
// Merge obj1 & obj2 to result
var result2 = _.merge( {}, obj1, obj2 );
Utiliser _.extend () - Link
// Merge obj1 & obj2 to result
var result3 = _.extend( {}, obj1, obj2 );
Utilisation de Object.assign () ECMAScript 2015 (ES6) - Lien
// Merge obj1 & obj2 to result
var result4 = Object.assign( {}, obj1, obj2 );
Sortie de tous
obj1: { animal: 'dog' }
obj2: { food: 'pizza', car: 'ford' }
result1: {food: "pizza", car: "ford", animal: "dog"}
result2: {food: "pizza", car: "ford", animal: "dog"}
result3: {food: "pizza", car: "ford", animal: "dog"}
result4: {food: "pizza", car: "ford", animal: "dog"}
ES2018/TypeScript: de nombreuses réponses sont correctes, mais j'ai proposé une solution plus élégante à ce problème lorsque vous devez fusionner deux objets sans écraser les clés d'objet qui se chevauchent .
Ma fonction accepte également nombre illimité d'objets à fusionner en tant qu'arguments de fonction:
(J'utilise la notation TypeScript ici, n'hésitez pas à supprimer le type :object[]
dans l'argument de la fonction si vous utilisez du code JavaScript simple).
const merge = (...objects: object[]) => {
return objects.reduce((prev, next) => {
Object.keys(prev).forEach(key => {
next[key] = { ...next[key], ...prev[key] }
})
return next
})
}
function extend(o, o1, o2){
if( !(o instanceof Object) ) o = {};
copy(o, o1);
if( o2 )
copy(o, o2)
function isObject(obj) {
var type = Object.prototype.toString.call(obj);
return obj === Object(obj) && type != '[object Array]' && type != '[object Function]';
};
function copy(a,b){
// copy o2 to o
for( var key in b )
if( b.hasOwnProperty(key) ){
if( isObject(b[key]) ){
if( !isObject(a[key]) )
a[key] = Object.assign({}, b[key]);
else copy(a[key], b[key])
}
else
a[key] = b[key];
}
}
return o;
};
var o1 = {a:{foo:1}, b:1},
o2 = {a:{bar:2}, b:[1], c:()=>{}},
newMerged = extend({}, o1, o2);
console.log( newMerged )
console.log( o1 )
console.log( o2 )
extension de la méthode de David Coallier par Gossi:
Vérifiez ces deux lignes:
from = arguments[i];
Object.getOwnPropertyNames(from).forEach(function (name) {
Il faut vérifier "de" par rapport à un objet null ... Si, par exemple, la fusion d’un objet provenant d’une réponse Ajax créée précédemment sur un serveur, une propriété d’objet peut avoir la valeur "null", et Dans ce cas, le code ci-dessus génère une erreur disant:
"de" n'est pas un objet valide
Ainsi, par exemple, en encapsulant la fonction "... Object.getOwnPropertyNames (from) .forEach ..." avec un "if (from! = Null) {...}", vous éviterez cette erreur.
Utilisation:
//Takes any number of objects and returns one merged object
var objectMerge = function(){
var out = {};
if(!arguments.length)
return out;
for(var i=0; i<arguments.length; i++) {
for(var key in arguments[i]){
out[key] = arguments[i][key];
}
}
return out;
}
Il a été testé avec:
console.log(objectMerge({a:1, b:2}, {a:2, c:4}));
Il en résulte:
{ a: 2, b: 2, c: 4 }
Ma façon:
function mergeObjects(defaults, settings) {
Object.keys(defaults).forEach(function(key_default) {
if (typeof settings[key_default] == "undefined") {
settings[key_default] = defaults[key_default];
} else if (isObject(defaults[key_default]) && isObject(settings[key_default])) {
mergeObjects(defaults[key_default], settings[key_default]);
}
});
function isObject(object) {
return Object.prototype.toString.call(object) === '[object Object]';
}
return settings;
}
:)
Voici ce que j'ai utilisé dans ma base de code pour fusionner.
function merge(to, from) {
if (typeof to === 'object' && typeof from === 'object') {
for (var pro in from) {
if (from.hasOwnProperty(pro)) {
to[pro] = from[pro];
}
}
}
else{
throw "Merge function can apply only on object";
}
}
Je commence à utiliser JavaScript, corrigez-moi si je me trompe.
Mais ne serait-il pas préférable de fusionner un certain nombre d'objets? Voici comment je le fais en utilisant l'objet natif Arguments
.
La clé est que vous pouvez réellement transmettre un nombre quelconque d'arguments à une fonction JavaScript sans les définir dans la déclaration de fonction. Vous ne pouvez simplement pas y accéder sans utiliser l'objet Arguments.
function mergeObjects() (
var tmpObj = {};
for(var o in arguments) {
for(var m in arguments[o]) {
tmpObj[m] = arguments[o][m];
}
}
return tmpObj;
}
La mise en œuvre correcte dans Prototype devrait ressembler à ceci:
var obj1 = {food: 'pizza', car: 'ford'}
var obj2 = {animal: 'dog'}
obj1 = Object.extend(obj1, obj2);
Pour ceux qui utilisent Node.js , il existe un module NPM: node.extend
npm install node.extend
var extend = require('node.extend');
var destObject = extend(true, {}, sourceObject);
// Where sourceObject is the object whose properties will be copied into another.
Vous pouvez fusionner des objets en suivant ma méthode
var obj1 = { food: 'pizza', car: 'ford' };
var obj2 = { animal: 'dog' };
var result = mergeObjects([obj1, obj2]);
console.log(result);
document.write("result: <pre>" + JSON.stringify(result, 0, 3) + "</pre>");
function mergeObjects(objectArray) {
if (objectArray.length) {
var b = "", i = -1;
while (objectArray[++i]) {
var str = JSON.stringify(objectArray[i]);
b += str.slice(1, str.length - 1);
if (objectArray[i + 1]) b += ",";
}
return JSON.parse("{" + b + "}");
}
return {};
}
ES5 one-liner natif compatible:
var merged = [obj1, obj2].reduce(function(a, o) { for(k in o) a[k] = o[k]; return a; }, {})
J'encourage l'utilisation et l'utilisation de méthodes non destructives qui ne modifient pas le source d'origine. 'Object.assign' est une méthode destructive et il se trouve qu'elle n'est pas non plus conviviale pour la production car elle cesse de fonctionner navigateurs antérieurs et vous n’avez aucun moyen de le corriger proprement, avec une alternative.
La fusion d'objets JS sera toujours hors de portée ou incomplète, quelle que soit la solution. Cependant, la fusion d’objets compatibles compatibles JSON n’est qu’à une étape de l’écriture d’un morceau de code simple et portable d’une méthode non destructive de fusion de séries d’objets JS dans un maître renvoyé contenant tous les noms de propriété uniques et leurs valeurs correspondantes synthétisées. un seul objet principal aux fins prévues.
Avoir en tête que MSIE8 est le premier navigateur à avoir ajouté une prise en charge native de l'objet JSON est un grand soulagement et réutiliser la technologie existante est toujours une opportunité bienvenue.
Restreindre votre code à des objets standard compatibles JSON est plus un avantage qu'une restriction, car ces objets peuvent également être transmis sur Internet. Et bien sûr, pour ceux qui souhaitent une compatibilité ascendante plus profonde, il y a toujours un plug-in Json, dont les méthodes peuvent facilement être assignées à une variable JSON dans le code externe sans avoir à modifier ou à réécrire la méthode utilisée.
function Merge( ){
var a = [].slice.call( arguments ), i = 0;
while( a[i] )a[i] = JSON.stringify( a[i++] ).slice( 1,-1 );
return JSON.parse( "{"+ a.join() +"}" );
}
(Bien sûr, on peut toujours lui donner un nom plus significatif, ce que je n’ai pas encore décidé; je devrais probablement le nommer JSONmerge)
Le cas d'utilisation:
var master = Merge( obj1, obj2, obj3, ...objn );
Or, contrairement au Object.assign
, tous les objets restent intacts et dans leur état d'origine (au cas où vous auriez commis une erreur et que vous auriez besoin de réorganiser les objets fusionnés ou de pouvoir les utiliser séparément pour une autre opération avant de les fusionner à nouveau).
Le nombre des arguments de fusion est également limité seulement par la limite de longueur des arguments [qui est énorme]. L’analyse/stringify JSON prise en charge en mode natif est déjà optimisée, ce qui signifie qu’elle devrait être plus rapide que toute forme de boucle JS scriptée. L’itération sur des arguments donnés est effectuée à l’aide de la while
- qui s’avère être la boucle la plus rapide de JS.
Il n’est pas inutile de mentionner brièvement le fait que nous savons déjà que les propriétés en double des étiquettes d’objet uniques (clés) seront écrasées par le dernier objet contenant le même libellé de clé, ce qui signifie que vous contrôlez quelle propriété est en train de prendre la relève. previous simplement en commandant ou en réordonnant la liste des arguments. Et l'avantage d'obtenir un objet maître propre et mis à jour, sans dupes en tant que sortie finale.
Cette solution crée un nouvel objet et est capable de gérer plusieurs objets.
De plus, il s’agit de récursif et vous pouvez choisir le temps que vous voulez pour remplacer les valeurs et Objets.
function extendObjects() {
var newObject = {};
var overwriteValues = false;
var overwriteObjects = false;
for ( var indexArgument = 0; indexArgument < arguments.length; indexArgument++ ) {
if ( typeof arguments[indexArgument] !== 'object' ) {
if ( arguments[indexArgument] == 'overwriteValues_True' ) {
overwriteValues = true;
} else if ( arguments[indexArgument] == 'overwriteValues_False' ) {
overwriteValues = false;
} else if ( arguments[indexArgument] == 'overwriteObjects_True' ) {
overwriteObjects = true;
} else if ( arguments[indexArgument] == 'overwriteObjects_False' ) {
overwriteObjects = false;
}
} else {
extendObject( arguments[indexArgument], newObject, overwriteValues, overwriteObjects );
}
}
function extendObject( object, extendedObject, overwriteValues, overwriteObjects ) {
for ( var indexObject in object ) {
if ( typeof object[indexObject] === 'object' ) {
if ( typeof extendedObject[indexObject] === "undefined" || overwriteObjects ) {
extendedObject[indexObject] = object[indexObject];
}
extendObject( object[indexObject], extendedObject[indexObject], overwriteValues, overwriteObjects );
} else {
if ( typeof extendedObject[indexObject] === "undefined" || overwriteValues ) {
extendedObject[indexObject] = object[indexObject];
}
}
}
return extendedObject;
}
return newObject;
}
var object1 = { a : 1, b : 2, testArr : [888, { innArr : 1 }, 777 ], data : { e : 12, c : { lol : 1 }, rofl : { O : 3 } } };
var object2 = { a : 6, b : 9, data : { a : 17, b : 18, e : 13, rofl : { O : 99, copter : { mao : 1 } } }, hexa : { tetra : 66 } };
var object3 = { f : 13, g : 666, a : 333, data : { c : { xD : 45 } }, testArr : [888, { innArr : 3 }, 555 ] };
var newExtendedObject = extendObjects( 'overwriteValues_False', 'overwriteObjects_False', object1, object2, object3 );
Contenu de newExtendedObject:
{"a":1,"b":2,"testArr":[888,{"innArr":1},777],"data":{"e":12,"c":{"lol":1,"xD":45},"rofl":{"O":3,"copter":{"mao":1}},"a":17,"b":18},"hexa":{"tetra":66},"f":13,"g":666}
Fiddle: http://jsfiddle.net/o0gb2umb/
J'ai utilisé Object.create () pour conserver les paramètres par défaut (en utilisant __proto__ ou Object.getPrototypeOf ()).
function myPlugin( settings ){
var defaults = {
"keyName": [ "string 1", "string 2" ]
}
var options = Object.create( defaults );
for (var key in settings) { options[key] = settings[key]; }
}
myPlugin( { "keyName": ["string 3", "string 4" ] } );
De cette façon, je peux toujours 'concat ()' ou 'Push ()' plus tard.
var newArray = options['keyName'].concat( options.__proto__['keyName'] );
Remarque : Vous devez effectuer une vérification hasOwnProperty avant la concaténation pour éviter les doublons.
Un moyen possible d'y parvenir est le suivant.
if (!Object.prototype.merge){
Object.prototype.merge = function(obj){
var self = this;
Object.keys(obj).forEach(function(key){
self[key] = obj[key]
});
}
};
Je ne sais pas si c'est mieux que les autres réponses. Dans cette méthode, vous ajoutez le prototype merge function
à Objects
. De cette façon, vous pouvez appeler obj1.merge(obj2);
Remarque: vous devez valider votre argument pour voir si c'est un objet et "jeter" une Error
appropriée. Sinon, Object.keys
"jettera" une "erreur"
Avec l’assistant suivant, vous pouvez fusionner deux objets en un nouvel objet:
function extend(obj, src) {
for (var key in src) {
if (src.hasOwnProperty(key)) obj[key] = src[key];
}
return obj;
}
// example
var a = { foo: true }, b = { bar: false };
var c = extend(a, b);
console.log(c);
// { foo: true, bar: false }
Cela est généralement utile lors de la fusion d'un dict d'options avec les paramètres par défaut d'une fonction ou d'un plugin.
Si la prise en charge de IE 8 n'est pas requise, vous pouvez utiliser Object.keys
pour la même fonctionnalité:
function extend(obj, src) {
Object.keys(src).forEach(function(key) { obj[key] = src[key]; });
return obj;
}
Cela implique un peu moins de code et est un peu plus rapide.
let obj1 = {a:1, b:2};
let obj2 = {c:3, d:4};
let merged = {...obj1, ...obj2};
console.log(merged);
A={a:1,b:function(){alert(9)}}
B={a:2,c:3}
A.merge = function(){for(var i in B){A[i]=B[i]}}
A.merge()
Le résultat est: {a: 2, c: 3, b: function ()}
Cela fusionne obj
dans une "valeur par défaut" def
. obj
a la priorité pour tout ce qui existe dans les deux, puisque obj
est copié dans def
Notez également que ceci est récursif.
function mergeObjs(def, obj) {
if (typeof obj == 'undefined') {
return def;
} else if (typeof def == 'undefined') {
return obj;
}
for (var i in obj) {
if (obj[i] != null && obj[i].constructor == Object) {
def[i] = mergeObjs(def[i], obj[i]);
} else {
def[i] = obj[i];
}
}
return def;
}
a = {x : {y : [123]}}
b = {x : {z : 123}}
console.log(mergeObjs(a, b));
// {x: {y : [123], z : 123}}
Nous pouvons créer un objet vide et les combiner par for-loop
:
var obj1 = {
id: '1',
name: 'name'
}
var obj2 = {
c: 'c',
d: 'd'
}
var obj3 = {}
for (var attrname in obj1) { obj3[attrname] = obj1[attrname]; }
for (var attrname in obj2) { obj3[attrname] = obj2[attrname]; }
console.log( obj1, obj2, obj3)
Si vous utilisez Dojo Toolkit , le meilleur moyen de fusionner deux objets consiste à utiliser un mixin.
Vous trouverez ci-dessous un exemple de mixin Dojo Toolkit:
// Dojo 1.7+ (AMD)
require(["dojo/_base/lang"], function(lang){
var a = { b:"c", d:"e" };
lang.mixin(a, { d:"f", g:"h" });
console.log(a); // b:c, d:f, g:h
});
// Dojo < 1.7
var a = { b:"c", d:"e" };
dojo.mixin(a, { d:"f", g:"h" });
console.log(a); // b:c, d:f, g:h
Pour plus de détails, veuillez mixin.
Vous pouvez affecter à chaque objet une méthode de fusion par défaut (peut-être une méthode "hériter" d'un meilleur nom):
Il devrait fonctionner avec des objets ou des fonctions instanciées.
Le code ci-dessous gère le remplacement des valeurs fusionnées si vous le souhaitez:
Object.prototype.merge = function(obj, override) {
// Don't override by default
for (var key in obj) {
var n = obj[key];
var t = this[key];
this[key] = (override && t) ? n : t;
};
};
Les données de test sont ci-dessous:
var Mammal = function () {
this.eyes = 2;
this.thinking_brain = false;
this.say = function () {
console.log('screaming like a mammal')};
}
var Human = function () {
this.thinking_brain = true;
this.say = function() {console.log('shouting like a human')};
}
john = new Human();
// Extend mammal, but do not override from mammal
john.merge(new Mammal());
john.say();
// Extend mammal and override from mammal
john.merge(new Mammal(), true);
john.say();
Une autre méthode:
function concat_collection(obj1, obj2) {
var i;
var arr = new Array();
var len1 = obj1.length;
for (i=0; i<len1; i++) {
arr.Push(obj1[i]);
}
var len2 = obj2.length;
for (i=0; i<len2; i++) {
arr.Push(obj2[i]);
}
return arr;
}
var ELEMENTS = concat_collection(A,B);
for(var i = 0; i < ELEMENTS.length; i++) {
alert(ELEMENTS[i].value);
}