2009-05-22 6 views
20

Jeśli posiadam obiekt javascript/assoc. tablica zdefiniowana w ten sposób:Jak scalić 2 obiekty javascript, zapełniając właściwości w jednym, jeśli nie istnieją w drugim?

function somefunction(options) { 

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

    //Do stuff here 

} 

i chcę użyć tego jako wartości domyślnych dla funkcji. Kiedy funkcja zostanie wywołana, chcę zapełnić zmienną options wartościami defaults, ale tylko wtedy, gdy nie istnieją one w options.

Więc powiedzmy, że ten nazwano

somefunction({ prop1: 'fish' }); 

Jak mogę sprawić, aby to options zostanie połączona z defaults takie, że mogę to

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

Odpowiedz

12

Można spojrzeć na funkcje jQuery lub Prototypy extend.

Wygląda to tak: (zaczerpnięte bezpośrednio z 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

Wygląda strasznie dużo pracy, aby wykonać jakąś głęboką kopię magii - jest to naprawdę konieczne ? – TML

+0

To dobre pytanie, rzeczy na głęboką kopię mogą być przesadzone. – cgp

+6

To nie jest kod, który musisz napisać, tak właśnie wygląda funkcja rozszerzenia, wszystko co musiałem zrobić, to opcje = $ .extend (domyślne, opcje) –

42

Po ponownym przeczytaniu pytanie, zorientowałeś się, że prawdopodobnie szukasz czegoś więcej:

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

dziękuję, powinno to być zaakceptowane odpowiedź :) – 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

Jestem holdout PrototypeJS. Typy Java nas preferują projekt OO PrototypeJS nad jQuery. Oto jak scalić dwa Object/Hash/Mapy z Proto:

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

obj1 wejście i obj2 są nienaruszone. pozycje mapy obj2 mają pierwszeństwo (tj. obj1 i obj2 mają ten sam klucz, wartość dla tego klucza w obj2 zastąpi).

+3

Jestem ciekawy, jak to jest bardziej zrozumiałe ... – boatcoder

+0

Dobry dla ciebie. Lepiej spytaj kogoś, kto uważa, że ​​jest to bardziej zrozumiałe. Właśnie informowałem, jak to zrobić z PrototypeJS dla tych, którzy chcą zrobić to z PrototypeJS. Nie ma tu znaczenia innego niż dla trolli, ale ja lubię JQuery dla operacji na listach. Niestety zawsze musisz używać operatorów list, podczas gdy ja najczęściej chcę operować na prostych obiektach skalarnych. – Blaine

1

Korzystanie Zamknięcie biblioteki Google można to zrobić tak:

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. 
} 
Powiązane problemy