0

I have a function which may be called with an optional object containing multiple options, each of which should fall back to a default value if omitted.

I'm currently doing this like so:

function f(options){
    var _options = options || {};
    _options.propertyOne = options.propertyOne || 50;
    _options.propertyTwo = options.propertyOne || 100;
    _options.propertyThree = options.propertyThree || {};
    _options.propertyThree.subPropOne = options.propertyThree.subPropOne || 150;

    //etc...
}

var options = {
    propertyOne: 20,
    propertyThree: {
        subPropOne: 100
    }
}

f(options);

However, as the number of options grows, the code is looking increasingly messy. There's also the potential problem of false/zero values being ignored (though all properties are currently numerical and non-zero).

Is there a more effective, more concise way of achieving this? I've considered creating an object initialised to default values within my function, then recursively copying any options supplied in the argument to it, but I'm not sure if doing so could introduce new problems that I haven't thought of yet.

Edit:

The function I would use to recursively copy properties:

function copyOptions(from, to){
    for(var i in from){
        if(typeof from[i] == "object"){
            to[i] = copyOptions(from[i], to[i]);
        }else if(typeof from[i] != "undefined"){
            to[i] = from[i];
        }
    }
}
Jim
  • 713
  • 1
  • 6
  • 23
  • 1
    Using an object an copying the properties would be the way to go. Instead of creating it inside the function, you could also create it as property of the function or use an immediate function to create a private scope and define the default options there. – Felix Kling May 30 '12 at 09:52
  • in plain javascript this could be useful: http://stackoverflow.com/questions/171251/how-can-i-merge-properties-of-two-javascript-objects-dynamically - the idea is to merge two different objects, like it happens on jQuery plugin with `$.merge` – Fabrizio Calderan May 30 '12 at 09:53
  • I've edited the question to include the recursive alternative I'm considering, does that look correct? – Jim May 30 '12 at 09:59

1 Answers1

1

Give the below a try:

function f(options){
    var _options = {
        propertyOne: 50,
        propertyTwo = 100,
        propertyThree: {
            subPropOne: 150
        }
    }

    if(options !== undefined){
        for(i in options){
            _options[i] = options[i];
        }
    }
}

Then inside the function, use variable _options. You'd need to extend the loop as well to see if the typeof options[i] is an object, and then step into it, etc.

JoolzCheat
  • 261
  • 4
  • 8
  • That looks a lot like what I considered switching to, I edited my question to include the alternative I've considered. My function checks each individual property though, rather than just the object. Is your method logically equivalent, or would it overwrite _options[i] with undefined if the property isn't present in the supplied options object? – Jim May 30 '12 at 10:06
  • Yes it would copy across an element if the user passed an argument with it explicitly defined as undefined. I'm not sure why a user would go to the length of defining a property as undefined, but there you go. – JoolzCheat May 30 '12 at 10:10
  • I meant if a property is omitted in the options object altogether. At any rate, I've switched to using the recursive function which I edited into my question, and it seems to be working correctly - it's pretty close to your answer, so I'll mark as accepted. – Jim May 30 '12 at 10:15
  • 1
    If a property is omitted, it'll preserve the existing value in _options (your default values) – JoolzCheat May 30 '12 at 10:16