2009-05-22 4 views
20

Si j'ai un objet javascript/assoc. tableau défini comme ceci:Comment puis-je fusionner 2 objets javascript, en remplissant les propriétés dans un si elles n'existent pas dans l'autre?

function somefunction(options) { 

    var defaults = { 
     prop1: 'foo', 
     prop2: 'bar' 
    }; 

    //Do stuff here 

} 

et je veux utiliser cela comme valeurs par défaut pour la fonction. Donc, lorsque la fonction est appelée, je veux remplir la variable options avec les valeurs dans defaults, mais seulement si elles n'existent pas dans options.

permet donc dire que cela a été appelé

somefunction({ prop1: 'fish' }); 

Comment puis-je faire en sorte que options obtient fusionné avec defaults telle que je reçois ce

{ 
    prop1: 'fish', 
    prop2: 'bar' 
} 

Répondre

12

Vous pouvez consulter les fonctionnalités de jQuery ou Prototypes extend.

Il ressemble à ceci: (pris directement à partir jQuery)

jQuery.extend = jQuery.fn.extend = function() { 
    // copy reference to target object 
    var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options; 

    // Handle a deep copy situation 
    if (typeof target === "boolean") { 
     deep = target; 
     target = arguments[1] || {}; 
     // skip the boolean and the target 
     i = 2; 
    } 

    // Handle case when target is a string or something (possible in deep copy) 
    if (typeof target !== "object" && !jQuery.isFunction(target)) 
     target = {}; 

    // extend jQuery itself if only one argument is passed 
    if (length == i) { 
     target = this; 
     --i; 
    } 

    for (; i < length; i++) 
     // Only deal with non-null/undefined values 
     if ((options = arguments[ i ]) != null) 
      // Extend the base object 
      for (var name in options) { 
       var src = target[ name ], copy = options[ name ]; 

       // Prevent never-ending loop 
       if (target === copy) 
        continue; 

       // Recurse if we're merging object values 
       if (deep && copy && typeof copy === "object" && !copy.nodeType) 
        target[ name ] = jQuery.extend(deep, 
         // Never move original objects, clone them 
         src || (copy.length != null ? [ ] : { }) 
        , copy); 

       // Don't bring in undefined values 
       else if (copy !== undefined) 
        target[ name ] = copy; 

      } 

    // Return the modified object 
    return target; 
}; 
+0

Semble énormément de travail à faire un peu de magie de copie en profondeur - est-il vraiment nécessaire ? – TML

+0

C'est une bonne question, la copie en profondeur pourrait être trop lourde. – cgp

+6

Ce n'est pas le code que vous devez écrire, c'est à quoi ressemble la fonction extend, tout ce que j'avais à faire était options = $ .extend (defaults, options) –

42

Après re-lecture de la question, je réalisé que vous cherchez probablement quelque chose de plus comme ceci:

var a = { 'foo': 'bar', 'baz': 'bat' }; 
var b = { 'foo': 'quux' }; 
for (var prop in a) { 
    if (prop in b) { continue; } 
    b[prop] = a[prop]; 
} 
+3

Merci beaucoup, cela devrait être la réponse acceptée :) – Phradion

1
<html> 
<head> 
<title>Testing</title> 

<script type="text/JavaScript"> 
// The method is simpler than its demonstration: 

function merge(obj1, obj2, force){ 
    for(var p in obj2){ 
     if(force || obj1[p]=== undefined) obj1[p]= obj2[p]; 
    } 
    return obj1; 
} 

// demo: 
var merge_demo= function(){ 
    // set up a to string method, just for the demo 
    var restring= function(){ 
     var s= []; 
     for(var p in this){ 
      s[s.length]= p+': '+this[p]; 
     } 
     return '{ '+s.join(', ')+' }'; 
    } 
    // define two objects 
    var O1={ 
     a: 1, b: 2, c: 3 
    } 
    var O2={ 
     a: 10, b: 11, d: 4 
    } 
    // Begin demo, write the object contents to a string: 
    var str= 'Object1='+restring.call(O1)+'\nObject2='+restring.call(O2)+'\n\n'; 

    //merge the two objects without overwriting values: 
    merge(O1, O2); 

    // Update object contents in string: 
    str+= 'merge(Object1,Object2)='+restring.call(O1)+'\n\n'; 

    //merge and replace existing values: 
    merge(O1, O2, true); 

    // Update and return string: 
    str+= 'merge(Object1,Object2,true)='+restring.call(O1); 
    return str; 
} 
alert(merge_demo()); 
</script> 
</head> 

<body> 
</body> 
</html> 
2

Je suis un holdout prototypejs. Les Java-types préfèrent le design OO de PrototypeJS sur jQuery. Voici comment fusionner deux objets/Hash/Maps avec Proto:

$H(obj1).merge(obj2).toObject() 

Le obj1 d'entrée et obj2 ne sont pas affectés. Les entrées de mappage obj2 ont la priorité (par exemple, obj1 et obj2 ont la même clé, la valeur de cette clé dans obj2 est prioritaire).

+3

Je suis curieux de savoir comment cela est plus compréhensible .... – boatcoder

+0

Bon pour vous. Vous feriez mieux de demander à quelqu'un qui pense que c'est plus compréhensible. J'informais juste comment le faire avec PrototypeJS pour ceux qui veulent le faire avec PrototypeJS. N'a aucune pertinence ici autre que pour les trolls, mais j'aime JQuery pour les opérations de liste. Malheureusement, vous devez toujours utiliser des opérateurs de liste, alors que je veux le plus souvent utiliser des objets scalaires simples. – Blaine

1

Utilisation de Google Closure Library, il peut être fait comme ça:

goog.require('goog.object'); 
function somefunction(options) { 
    var defaults = { 
    prop1: 'foo', 
    prop2: 'bar' 
    }; 
    goog.object.extend(defaults, options); 
    // if the property is defined in options it will overwrite value. 
} 
Questions connexes