69

I have a typical javascript function with some parameters

my_function = function(content, options) { action }

if I call the function as such :

my_function (options)

the argument "options" is passed as "content"

how do i go around this so I can either have both arguments passed or just one ? thank you

Strategy Thinker
  • 343
  • 1
  • 3
  • 15
salmane
  • 4,799
  • 13
  • 48
  • 61

13 Answers13

101

You have to decide as which parameter you want to treat a single argument. You cannot treat it as both, content and options.

I see two possibilities:

  1. Either change the order of your arguments, i.e. function(options, content)
  2. Check whether options is defined:

    function(content, options) {
        if(typeof options === "undefined") {
            options = content;
            content = null;
        }
        //action
    }
    

    But then you have to document properly, what happens if you only pass one argument to the function, as this is not immediately clear by looking at the signature.

Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
  • 1
    undefined is a global property with a constant value, as such you don't need to quote it. In obsolete browsers you could accidentally set it to an arbitrary value, but this is not the case of modern-day browsers. – andreszs Aug 12 '14 at 17:52
  • 5
    @Andrew: `typeof` always returns a string. Alternatively, `if (options === undefined)` would work as well. But as you said, it is possible to override `undefined` in older browsers, so still prevalent practice (I think) is to not directly use `undefined` (unless you defined somewhere explicitly). – Felix Kling Aug 12 '14 at 17:54
  • 1
    do not compare strings with `===`, those are not necessairy the same Object if thy have the same content. – inetphantom Mar 15 '16 at 09:47
  • 2
    @inetphantom: not sure what you are saying. That doesn't make sense. Primitive strings are not objects anyway. – Felix Kling Mar 15 '16 at 14:40
  • if you know that `content` and `options` will NOT be of the same type you can check for type of `content` and swap if need be. I also see people counting arguments to do this. Checking `content` instead of `options` also provides some additional argument validation – DKebler Feb 21 '19 at 22:38
29
my_function = function(hash) { /* use hash.options and hash.content */ };

and then call:

my_function ({ options: options });
my_function ({ options: options, content: content });
borisdiakur
  • 10,387
  • 7
  • 68
  • 100
Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
22

Like this:

my_function (null, options) // for options only
my_function (content) // for content only
my_function (content, options) // for both
Sarfraz
  • 377,238
  • 77
  • 533
  • 578
16

With ES6:

function test(a, b = 3) {
   console.log(a, b);
}

test(1);      // Output: 1 3
test(1, 2);   // Output: 1 2
ulou
  • 5,542
  • 5
  • 37
  • 47
5

Or you also can differentiate by what type of content you got. Options used to be an object the content is used to be a string, so you could say:

if ( typeof content === "object" ) {
  options = content;
  content = null;
}

Or if you are confused with renaming, you can use the arguments array which can be more straightforward:

if ( arguments.length === 1 ) {
  options = arguments[0];
  content = null;
}
gblazex
  • 49,155
  • 12
  • 98
  • 91
3

There is a nice read on Default parameters in ES6 on the MDN website here.
In ES6 you can now do the following:

secondDefaultValue = 'indirectSecondDefaultValue';

function MyObject( param1 = 'firstDefaultValue', param2 = secondDefaultValue ){
    this.first = param1;
    this.second = param2;
}

You can use this also as follows:

var object = new MyObject( undefined, options );

Which will set default value 'firstDefaultValue' for first param1 and your options for second param2.

Here a demonstration in a fiddle

Wilt
  • 41,477
  • 12
  • 152
  • 203
2

There are 2 ways to do this.

1)

function something(options) {
    var timeToLive = options.timeToLive || 200; // default to 200 if not set
    ...
}

2)

function something(timeToDie /*, timeToLive*/) {
    var timeToLive = arguments[1] || 200; // default to 200 if not set
    ..
}

In 1), options is a JS object with what ever attributes are required. This is easier to maintain and extend.

In 2), the function signature is clear to read and understand that a second argument can be provided. I've seen this style used in Mozilla code and documentation.

DynamicDan
  • 425
  • 4
  • 12
2

I've created a simple library for handling optional arguments with JavaScript functions, see https://github.com/ovatto/argShim. The library is developed with Node.js in mind but should be easily ported to work with e.g. browsers.

Example:

var argShim = require('argShim');
var defaultOptions = {
  myOption: 123
};

var my_function = argShim([
    {optional:'String'},
    {optional:'Object',default:defaultOptions}
  ], function(content, options) {
    console.log("content:", content, "options:", options);
  });

my_function();
my_function('str');
my_function({myOption:42});
my_function('str', {myOption:42});

Output:

content: undefined options: { myOption: 123 }
content: str options: { myOption: 123 }
content: undefined options: { myOption: 42 }
content: str options: { myOption: 42 }

The main target for the library are module interfaces where you need to be able to handle different invocations of exported module functions.

ovatto
  • 21
  • 1
  • This is very verbose, plus it uses the word "default" which is already a keyword in JS. Would not recommend. – Domino Jan 05 '16 at 16:56
  • Sure it may be a bit verbose but it does provide some added features on top of simple argument presence checking. And writing same features in each function is bound to be even more verbose. Also while some don't like it reserved keywords can freely be used as property names in ES5. However the whole lib was pretty hastily written so your (and mine) mileage may vary :) – ovatto Jun 10 '16 at 07:32
1

You can pass all your optional arguments in an object as the first argument. The second argument is your callback. Now you can accept as many arguments as you want in your first argument object, and make it optional like so:

function my_func(op, cb) {
    var options = (typeof arguments[0] !== "function")? arguments[0] : {},
        callback = (typeof arguments[0] !== "function")? arguments[1] : arguments[0];

    console.log(options);
    console.log(callback);
}

If you call it without passing the options argument, it will default to an empty object:

my_func(function () {});
=> options: {}
=> callback: function() {}

If you call it with the options argument you get all your params:

my_func({param1: 'param1', param2: 'param2'}, function () {});
=> options: {param1: "param1", param2: "param2"}
=> callback: function() {}

This could obviously be tweaked to work with more arguments than two, but it get's more confusing. If you can just use an object as your first argument then you can pass an unlimited amount of arguments using that object. If you absolutely need more optional arguments (e.g. my_func(arg1, arg2, arg3, ..., arg10, fn)), then I would suggest using a library like ArgueJS. I have not personally used it, but it looks promising.

skinneejoe
  • 3,921
  • 5
  • 30
  • 45
  • thanks a lot... Exactly I'm searching for this. I have a 6 parameters in my function. some parameters have a default values. But some parameters should set in function call. I think this answer will well suited to my case. Thanks again... :) – CJ Ramki Aug 26 '14 at 09:22
1

Just to kick a long-dead horse, because I've had to implement an optional argument in the middle of two or more required arguments. Use the arguments array and use the last one as the required non-optional argument.

my_function() {
  var options = arguments[argument.length - 1];
  var content = arguments.length > 1 ? arguments[0] : null;
}
ant
  • 243
  • 2
  • 8
0

You will get the un passed argument value as undefined. But in your case you have to pass at least null value in the first argument.

Or you have to change the method definition like

my_function = function(options, content) { action }
Puru
  • 8,913
  • 26
  • 70
  • 91
-1

You could also put a check in the action like: options = !options ? content : options that sets options to the first argument if no second was passed in, and then you just set content to null (or ignore it, however you want to check that)

WFW
  • 125
  • 1
  • 9
-1

Call like this

my_function ("", options);
Muneer
  • 7,384
  • 7
  • 38
  • 62