Let's say you have this as the default parameters to something like a charts API

var defaultOptions = {

width: 20 ,

height:100,

title:"this is the default title",

type:"bar"

};

and you want to use most of those settings, but make just a couple of changes, with jQuery you can say

var options = jQuery.extend ( {

height:200,

type:"pie"

} , defaultOptions) ;

and you'll get back an object like this

{ width: 20 ,

height:200,

title:"this is the default title",

type:"pie"

};

Deeper

So far pretty simple .. but you may need to go deeper into the object if there are properties beyond the first level.

var defaultOptions = {

dimensions: {

width: 20 ,

height:100

},

title:"this is the default title",

type:"bar"

};

Still not too bad, but you'd have to do this. So you can imagine if you continue this out to multiple levels, we have a good candidate for a solution involving recursion

var options = cUseful.extend ( {

dimensions: {

height:200

}

type:"pie"

} , defaultOptions) ;

The cUseful library

Many of the snippets in this section of the site are part of the cUseful library. You can find the details below. This extend function uses a couple of functions from that, and will be implemented there too if you want to use it from a library.

Walkthrough

Since we have a variable number of arguments, we use the special arguments array like object to pick the up from - returning undefined if we don't get any.

// we have a variable number of arguments

if (!arguments.length) {

// default with no arguments is to return undefined

return undefined;

}

Pick up each of the objects from the arguments array, check that they are in fact objects, and set up the target from the first one, and note all of the extenders from which to apply their default values.

// validate we have all objects

var extenders = [],targetOb;

for (var i = 0; i < arguments.length; i++) {

if (!isObject(arguments[i])) {

throw 'extend arguments must be objects';

}

if (i ===0 ) {

targetOb = arguments[i];

}

else {

extenders.push (arguments[i]);

}

}

For each of those extenders, apply their defaults. We have to do it recursively as each property of each extender may have sub properties.

// set defaults from extender objects

extenders.forEach(function(d) {

recurse(targetOb, d);

});

return targetOb;

Here's the recursive function - it calls itself with the properties at the current level if any of them are an object so that matching properties from the default objects can be applied. These are analogous to the children in JavaScript recursion primer

// run do a deep check

function recurse(tob,sob) {

Object.keys(sob).forEach(function (k) {

// if target ob is completely undefined, then copy the whole thing

if (isUndefined(tob[k])) {

tob[k] = sob[k];

}

// if source ob is an object then we need to recurse to find any missing items in the target ob