Handling optional parameters in javascript

You can know how many arguments were passed to your function and you can check if your second argument is a function or not:

function getData (id, parameters, callback) {
  if (arguments.length == 2) { // if only two arguments were supplied
    if (Object.prototype.toString.call(parameters) == "[object Function]") {
      callback = parameters; 
    }
  }
  //...
}

You can also use the arguments object in this way:

function getData (/*id, parameters, callback*/) {
  var id = arguments[0], parameters, callback;

  if (arguments.length == 2) { // only two arguments supplied
    if (Object.prototype.toString.call(arguments[1]) == "[object Function]") {
      callback = arguments[1]; // if is a function, set as 'callback'
    } else {
      parameters = arguments[1]; // if not a function, set as 'parameters'
    }
  } else if (arguments.length == 3) { // three arguments supplied
      parameters = arguments[1];
      callback = arguments[2];
  }
  //...
}

If you are interested, give a look to this article by John Resig, about a technique to simulate method overloading on JavaScript.


Er - that would imply that you are invoking your function with arguments which aren't in the proper order... which I would not recommend.

I would recommend instead feeding an object to your function like so:

function getData( props ) {
    props = props || {};
    props.params = props.params || {};
    props.id = props.id || 1;
    props.callback = props.callback || function(){};
    alert( props.callback )
};

getData( {
    id: 3,
    callback: function(){ alert('hi'); }
} );

Benefits:

  • you don't have to account for argument order
  • you don't have to do type checking
  • it's easier to define default values because no type checking is necessary
  • less headaches. imagine if you added a fourth argument, you'd have to update your type checking every single time, and what if the fourth or consecutive are also functions?

Drawbacks:

  • time to refactor code

If you have no choice, you could use a function to detect whether an object is indeed a function ( see last example ).

Note: This is the proper way to detect a function:

function isFunction(obj) {
    return Object.prototype.toString.call(obj) === "[object Function]";
}

isFunction( function(){} )

You should check type of received parameters. Maybe you should use arguments array since second parameter can sometimes be 'parameters' and sometimes 'callback' and naming it parameters might be misleading.