views:

1431

answers:

4

If I have a javascript object/assoc. array defined like this:

function somefunction(options) {

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

    //Do stuff here

}

and I want to use this as the default values for the function. So when the function gets called I want to populate the options variable with the values in defaults, but only if they don't exist in options.

So lets say that this was called

somefunction({ prop1: 'fish' });

How can I make it so that options gets merged with defaults such that I get this

{
    prop1: 'fish',
    prop2: 'bar'
}
+10  A: 

After re-reading the question, I realized you're probably looking for something more like this:

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

You could look at either jQuery's or Prototypes extend functionality.

It looks like this: (taken directly from 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;
};
altCognito
Seems an awful lot of work to perform some deep copy magic - is it really necessary?
TML
That's a good question, the deep copy stuff could be overkill.
altCognito
That's not the code you need to write, that's what the extend function looks like, all I had to do was options = $.extend(defaults, options)
Glenn Slaven
I realize that he was sharing a jQuery method - but it does a lot of processing to perform 'deep copies', where the OP made it seem a simpler problem than that. Just something to keep in mind.
TML
A: 
<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>
kennebec
A: 

I'm a PrototypeJS holdout. Us Java-types prefer PrototypeJS's OO design over jQuery. Here's how you merge two Object/Hash/Maps with Proto:

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

The input obj1 and obj2 are unaffected. obj2 map entries have precedence (i.e. obj1 and obj2 both have same key, the value for that key in obj2 will override).