L'objet Javascript n'a pas d'opération de fusion native. Si vous avez deux objets, dites
{a:1, b:2}
{c:3, d:4}
Et je veux avoir
{a:1, b:2, c:3, d:4}
Pour autant que je sache, vous devez parcourir les objets. C'est-à-dire que vous décidez d'une stratégie de fusion gauche ou droite et ensuite vous faites quelque chose comme (simplifié)
for (key in object2) {
object1[key] = object2[key];
}
C'est bon. Cependant, Javascript a les fonctionnalités call
et prototype
. Par exemple, transformer arguments
en Array
peut être fait avec
Array.prototype.slice.call(arguments)
Cette approche exploite le code natif existant et est donc moins sensible à la folie du programmeur et devrait s'exécuter plus rapidement qu'une implémentation non native.
Y a-t-il une astuce pour utiliser ce prototype/modèle d'appel sur peut-être les fonctions de traversée Attribute
ou Node
du DOM, ou peut-être certaines des fonctions génériques String
afin de faire une fusion d'objets natifs?
Le code ressemblerait à ceci:
var merged = somethingrandom.obscuremethod.call(object1, object2)
Et par conséquent, vous obtiendriez une fusion native sans traversée.
Si vous pouviez utiliser la propriété constructor
d'un Object
, puis contraindre un objet à avoir un constructeur d'un autre objet, puis exécuter new
sur l'objet composite, vous pourriez obtenir un fusionner gratuitement. Mais je n'ai pas une bonne compréhension des implications complètes de la fonction constructor
en javascript pour effectuer cet appel.
La même question vaut pour Arrays
. Un problème courant consiste à prendre, disons, 7 tableaux de nombres, puis à essayer de trouver l'intersection de ces tableaux. C'est-à-dire, quels nombres existent dans les 7 tableaux.
Vous pouvez les concaténer ensemble, puis faire un tri, puis faire une traversée, sûrement. Mais ce serait bien s'il y avait une intersection générique cachée quelque part que nous pouvons contraindre un tableau à faire de manière native.
Des pensées?
éditer:
Pour le problème de tableau, vous pouvez procéder comme suit:
array.concat (a, b, c) .sort (). join (':') puis utilisez des schémas de capture et de répétition RegExp
délicats pour traverser. Les implémentations RegExp, si vous ne le savez pas, s'exécutent sur une machine virtuelle basée sur une pile très simple. Lorsque vous initialisez votre expression régulière, c'est vraiment un programme qui est compilé (RegExp.compile est une méthode JS obsolète). Ensuite, le natif parcourt la chaîne d'une manière incroyablement rapide. Peut-être pourriez-vous exploiter cela pour les seuils d'adhésion et obtenir de meilleures performances ...
Mais cela ne va pas jusqu'au bout.
Ma réponse sera décevante, mais quand même:
non
La raison en est simple: l'implémentation de fusion (ou "d'extension" comme on l'appelle pour les objets) de M. Resig dans jQuery fait une boucle, tout comme celle de votre question. Vous pouvez le regarder ici . Et j'ose dire que si John Resig n'a pas trouvé un moyen intelligent de le faire, les simples mortels de stackoverflow ne le seront pas non plus :)
La question à un million de dollars! J'ai essayé de le faire de nombreuses façons, et la boucle décrite ci-dessus a toujours semblé la plus sale. Object.setPrototypeOf()
d'ES6 vous permet de déléguer un objet "property override" à un objet "default properties", accomplissant à peu près ce que vous essayez de faire, mais l'utilisation de Object.setPrototypeOf()
a de sérieuses implications , comme désactiver les optimisations du compilateur du navigateur pour l'ensemble du script.
De plus, dans la solution de boucle et la solution Object.setPrototypeOf()
, vous vous retrouvez dans une situation où l'objet "property override" peut muter l'objet "default properties":
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.
Vous pourriez penser que ce n'est pas un problème, mais disons que vous utilisez cet objet comme configuration pour une bibliothèque tierce. Vous donnez maintenant le contrôle de votre objet par défaut et tout ce qui y est référencé à la bibliothèque tierce.
Une meilleure solution pourrait être d'utiliser JSON.stringify et JSON.parse pour copier et combiner les objets. Voici un Gist avec l'exemple: https://Gist.github.com/spikesagal/6f7822466887f19b9c65
HTH
Pas que je sache, non. De plus, vous voudrez écrire votre méthode de fusion comme ceci:
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;
}
En utilisant ES6 (ES2015), vous pouvez utiliser la méthode Object.assign:
var x = {a:1, b:2};
var y = {c:3, d:4};
var z = Object.assign({},x,y);
En utilisant ES7 (ES2016, Chrome 60+ ou Babel), vous pouvez utiliser Opérateur de propagation d'objet:
var x = {a:1, b:2};
var y = {c:3, d:4};
var z = {...x, ...y};
Vous pouvez effectuer les opérations suivantes à l'aide de JS 1.7 natif, sans avoir besoin d'un framework. Voir l'exemple sur violon (exemple destiné uniquement aux objets simples - pas aux objets imbriqués complexes)
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);
Pas de méthodes natives dans ECMA-Script, utilisez:
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;
}