836

I've always handled optional parameters in JavaScript like this:

function myFunc(requiredArg, optionalArg){
  optionalArg = optionalArg || 'defaultValue';

  // Do stuff
}

Is there a better way to do it?

Are there any cases where using || like that is going to fail?

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Mark Biek
  • 135,050
  • 52
  • 150
  • 195

28 Answers28

1084

Your logic fails if optionalArg is passed, but evaluates as false - try this as an alternative

if (typeof optionalArg === 'undefined') { optionalArg = 'default'; }

Or an alternative idiom:

optionalArg = (typeof optionalArg === 'undefined') ? 'default' : optionalArg;

Use whichever idiom communicates the intent best to you!

Paul Dixon
  • 277,937
  • 48
  • 303
  • 335
  • 83
    I'd user triple equals ('...lArg === "und...') to be on the safe side. – Jarrod Mar 05 '12 at 22:28
  • 3
    @Jarrod === is not necessary on typeof check since typeof returns a string, but no harm in doing so. – Ashwin Prabhu Oct 16 '12 at 07:51
  • 35
    It's probably best to make using === a habit so you don't have to remember under which circumstances it's 'safe'. – jinglesthula Oct 31 '12 at 20:38
  • 45
    Why use a ternary operator here? Isn't the 2nd clause just setting optionalArg = optionalArg?. I would think just a simple IF would do: if(typeof optionalArg === "undefined") optionalArg = "defaultValue"; – Shane N Dec 19 '12 at 18:50
  • 7
    Why use typeof? `optionalArg = (optionalArg === undefined) ? "defaultValue" : optionalArg;` – anatoly techtonik Feb 05 '13 at 17:15
  • 14
    I think it signals the intent better - typeof doesn't evaluate the operate, only inspects its type, which is what we're interested in. Also, evaluation will be around 40% slower (http://jsperf.com/stackoverflow148901) – Paul Dixon Feb 05 '13 at 17:56
  • I'm finding this problematic. Using this, it did not fix the error of an unset parameter being passed into my function. I console logged the value of the unset parameter I was passing in which was getting through this protective layer, and it came out as NaN. I don't understand why this answer is so popular when that value can get through. I ended up using isNaN() for my issue. – temporary_user_name Mar 21 '13 at 16:43
  • 13
    Well, you aren't talking about optional parameters - you really *are* passing a parameter, so this solution doesn't apply to your case. NaN doesn't mean "undefined" - it means you've passing a number but its value is NaN. See http://stackoverflow.com/questions/3215120/why-javascript-says-that-a-number-is-not-a-number for more – Paul Dixon Mar 22 '13 at 10:36
  • 8
    @PaulDixon just curious, as time goes on the benchmark results has been inverted (since Chrome 31) http://jsperf.com/stackoverflow148901 Seems like Chrome devs have optimised the more common method used – Jaime Agudo Apr 29 '14 at 09:48
  • 1
    optionalAgr = optionalAgr === undefined ? defaultValue : optionalArg; IMHO typeof is redundant optionalArg is always declared in the function scope. – Víctor Herraiz Sep 29 '14 at 15:16
  • 1
    My implementation on a toggle: direction = (typeof direction === 'undefined') ? whatever_it_was_by_default : (direction === 'in') ? true : false; – Robbie Smith Mar 30 '15 at 16:22
  • @ShaneN I don't think it matter in js, but the ternary is useful if you always want to assign _something_ to a variable. It is somewhat easier to parallelize if there are no if() branches. – Navin Apr 30 '15 at 02:22
  • why not just `optionalArg && foo` – SuperUberDuper Oct 19 '15 at 15:59
  • 1
    @SuperUberDuper - doesn't work for 'falsey' values – Paul Dixon Oct 19 '15 at 17:57
  • @PaulDixon how come? – SuperUberDuper Oct 20 '15 at 09:04
  • What about the parameter positions? `function(a, b, callback)` where b is optional. If you omit `b` (`function(a, callback)`) you might find yourself comparing the value of `callback` as if it was `b`. If there is no other option, I would suggest having a single json parameter and do the checks inside: `function(myObj)` -- then check inside for `myObj.b`, `myObj.callback`. – noderman Feb 23 '16 at 17:40
  • @noderman it is a standard in many languages that officially support optional params to have them come last. If there are more than one optional param, you can't omit the first and provide the second. If you want to provide the second, you must provide both. – Emile Bergeron Mar 07 '16 at 16:12
  • The function above ( `function(a, b, callback)` ) is very common on Node.js, where `callback` is **not** optional, but `b` can be. Of course, you can write the underlying function in a way to detect if the second parameter is a function or not (if function, then it is the required callback). – noderman Mar 07 '16 at 16:26
  • optionArg = !! optionArg ? optionArg : 'default'; – Paul Verschoor Mar 03 '18 at 11:14
165

In ECMAScript 2015 (aka "ES6") you can declare default argument values in the function declaration:

function myFunc(requiredArg, optionalArg = 'defaultValue') {
    // do stuff
}

More about them in this article on MDN.

This is currently only supported by Firefox, but as the standard has been completed, expect support to improve rapidly.


EDIT (2019-06-12):

Default parameters are now widely supported by modern browsers.
All versions of Internet Explorer do not support this feature. However, Chrome, Firefox, and Edge currently support it.

Arsen Khachaturyan
  • 6,472
  • 4
  • 32
  • 36
Lachlan Hunt
  • 2,342
  • 1
  • 13
  • 7
127

I find this to be the simplest, most readable way:

if (typeof myVariable === 'undefined') { myVariable = 'default'; }
//use myVariable here

Paul Dixon's answer (in my humble opinion) is less readable than this, but it comes down to preference.

insin's answer is much more advanced, but much more useful for big functions!

EDIT 11/17/2013 9:33pm: I've created a package for Node.js that makes it easier to "overload" functions (methods) called parametric.

trusktr
  • 34,715
  • 41
  • 148
  • 226
  • 3
    +1, but typeof returns a string, so you need to put quotes around undefined for this to work: `if(typeof myVariable == "undefined")`... – Richard Inglis Jun 04 '12 at 15:10
  • 3
    I made this answer, and the accepted answer, fight to the death. The accepter answer's ternary method was slightly slower for the handful of tests I ran: http://jsperf.com/optional-function-parameters-ternary-vs-manual – Jeromy French Feb 05 '15 at 22:48
  • 1
    @OmShankar It will make no difference. – BadHorsie Oct 29 '15 at 13:26
45

If you need to chuck a literal NULL in, then you could have some issues. Apart from that, no, I think you're probably on the right track.

The other method some people choose is taking an assoc array of variables iterating through the argument list. It looks a bit neater but I imagine it's a little (very little) bit more process/memory intensive.

function myFunction (argArray) {
    var defaults = {
        'arg1'  :   "value 1",
        'arg2'  :   "value 2",
        'arg3'  :   "value 3",
        'arg4'  :   "value 4"
    }

    for(var i in defaults) 
        if(typeof argArray[i] == "undefined") 
               argArray[i] = defaults[i];

    // ...
}
Oli
  • 215,718
  • 61
  • 207
  • 286
  • 4
    why not hasOwnProperty instead of == "undefined" ? – Cris Stringfellow Mar 04 '13 at 16:52
  • Why not `if (!(i in argArray))` instead? And for completeness, before this `if`-statement, there should be a check for the correct argument type, e.g. `if (typeof argArray !== "object") argArray = [];`. – Bart Aug 14 '14 at 13:32
33

Ideally, you would refactor to pass an object and merge it with a default object, so the order in which arguments are passed doesn't matter (see the second section of this answer, below).

If, however, you just want something quick, reliable, easy to use and not bulky, try this:


A clean quick fix for any number of default arguments

  • It scales elegantly: minimal extra code for each new default
  • You can paste it anywhere: just change the number of required args and variables
  • If you want to pass undefined to an argument with a default value, this way, the variable is set as undefined. Most other options on this page would replace undefined with the default value.

Here's an example for providing defaults for three optional arguments (with two required arguments)

function myFunc( requiredA, requiredB,  optionalA, optionalB, optionalC ) {

  switch (arguments.length - 2) { // 2 is the number of required arguments
    case 0:  optionalA = 'Some default';
    case 1:  optionalB = 'Another default';
    case 2:  optionalC = 'Some other default';
    // no breaks between cases: each case implies the next cases are also needed
  }

}

Simple demo. This is similar to roenving's answer, but easily extendible for any number of default arguments, easier to update, and using arguments not Function.arguments.


Passing and merging objects for more flexibility

The above code, like many ways of doing default arguments, can't pass arguments out of sequence, e.g., passing optionalC but leaving optionalB to fall back to its default.

A good option for that is to pass objects and merge with a default object. This is also good for maintainability (just take care to keep your code readable, so future collaborators won't be left guessing about the possible contents of the objects you pass around).

Example using jQuery. If you don't use jQuery, you could instead use Underscore's _.defaults(object, defaults) or browse these options:

function myFunc( args ) {
  var defaults = {
    optionalA: 'Some default',
    optionalB: 'Another default',
    optionalC: 'Some other default'
  };
  args = $.extend({}, defaults, args);
}

Here's a simple example of it in action.

Community
  • 1
  • 1
user56reinstatemonica8
  • 27,132
  • 16
  • 87
  • 109
  • Not sure I understand this one. Wouldn't it also replace the value when the parameter is actually given?! Oo – jeromej Jun 07 '14 at 19:34
  • Hey, this is about the cleanest way I have seen. The only problem with it is this: http://jsperf.com/optional-parameters-typeof-vs-switch The switch is apparently very slow.. – JDC Jun 19 '14 at 11:09
  • 6
    Not sure I'd call 23.6 million operations per second slow... it's true that `typeof` is incredibly fast, but that doesn't make `switch` slow - just not as incredibly fast. – user56reinstatemonica8 Jun 19 '14 at 21:43
18

You can use some different schemes for that. I've always tested for arguments.length:

function myFunc(requiredArg, optionalArg){
  optionalArg = myFunc.arguments.length<2 ? 'defaultValue' : optionalArg;

  ...

-- doing so, it can't possibly fail, but I don't know if your way has any chance of failing, just now I can't think up a scenario, where it actually would fail ...

And then Paul provided one failing scenario !-)

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
roenving
  • 2,372
  • 12
  • 14
13

Similar to Oli's answer, I use an argument Object and an Object which defines the default values. With a little bit of sugar...

/**
 * Updates an object's properties with other objects' properties. All
 * additional non-falsy arguments will have their properties copied to the
 * destination object, in the order given.
 */
function extend(dest) {
  for (var i = 1, l = arguments.length; i < l; i++) {
    var src = arguments[i]
    if (!src) {
      continue
    }
    for (var property in src) {
      if (src.hasOwnProperty(property)) {
        dest[property] = src[property]
      }
    }
  }
  return dest
}

/**
 * Inherit another function's prototype without invoking the function.
 */
function inherits(child, parent) {
  var F = function() {}
  F.prototype = parent.prototype
  child.prototype = new F()
  child.prototype.constructor = child
  return child
}

...this can be made a bit nicer.

function Field(kwargs) {
  kwargs = extend({
    required: true, widget: null, label: null, initial: null,
    helpText: null, errorMessages: null
  }, kwargs)
  this.required = kwargs.required
  this.label = kwargs.label
  this.initial = kwargs.initial
  // ...and so on...
}

function CharField(kwargs) {
  kwargs = extend({
    maxLength: null, minLength: null
  }, kwargs)
  this.maxLength = kwargs.maxLength
  this.minLength = kwargs.minLength
  Field.call(this, kwargs)
}
inherits(CharField, Field)

What's nice about this method?

  • You can omit as many arguments as you like - if you only want to override the value of one argument, you can just provide that argument, instead of having to explicitly pass undefined when, say there are 5 arguments and you only want to customise the last one, as you would have to do with some of the other methods suggested.
  • When working with a constructor Function for an object which inherits from another, it's easy to accept any arguments which are required by the constructor of the Object you're inheriting from, as you don't have to name those arguments in your constructor signature, or even provide your own defaults (let the parent Object's constructor do that for you, as seen above when CharField calls Field's constructor).
  • Child objects in inheritance hierarchies can customise arguments for their parent constructor as they see fit, enforcing their own default values or ensuring that a certain value will always be used.
Jonny Buchanan
  • 58,371
  • 16
  • 137
  • 146
9

Loose type checking

Easy to write, but 0, '', false, null and undefined will be converted to default value, which might not be expected outcome.

function myFunc(requiredArg, optionalArg) {
    optionalArg = optionalArg || 'defaultValue';
}

Strict type checking

Longer, but covers majority of cases. Only case where it incorrectly assigns default value is when we pass undefined as parameter.

function myFunc(requiredArg, optionalArg) {
    optionalArg = typeof optionalArg !== 'undefined' ? optionalArg : 'defaultValue';
}

Checking arguments variable

Catches all cases but is the most clumsy to write.

function myFunc(requiredArg, optionalArg1, optionalArg2) {
    optionalArg1 = arguments.length > 1 ? optionalArg1 : 'defaultValue';
    optionalArg2 = arguments.length > 2 ? optionalArg2 : 'defaultValue';
}

ES6

Unfortunately this has very poor browser support at the moment

function myFunc(requiredArg, optionalArg = 'defaultValue') {

}
Petr Hurtak
  • 2,063
  • 1
  • 17
  • 15
  • *"Checking arguments variable - Catches all cases but is the most clumsy to write"* And in loose mode can have negative performance implications thanks to using `arguments` (not that it usually matters). – T.J. Crowder Aug 19 '15 at 11:00
8

If you're using defaults extensively, this seems much more readable:

function usageExemple(a,b,c,d){
    //defaults
    a=defaultValue(a,1);
    b=defaultValue(b,2);
    c=defaultValue(c,4);
    d=defaultValue(d,8);

    var x = a+b+c+d;
    return x;
}

Just declare this function on the global escope.

function defaultValue(variable,defaultValue){
    return(typeof variable!=='undefined')?(variable):(defaultValue);
}

Usage pattern fruit = defaultValue(fruit,'Apple');

*PS you can rename the defaultValue function to a short name, just don't use default it's a reserved word in javascript.

Vitim.us
  • 16,145
  • 12
  • 81
  • 96
  • +1 because I was going to post my solution which is just the same: `function defaultFor(arg, val) { return typeof arg !== 'undefined' ? arg : val; }` – Camilo Martin Sep 02 '12 at 06:02
5

I am used to seeing a few basic variations on handling optional variables. Sometimes, the relaxed versions are useful.

function foo(a, b, c) {
  a = a || "default";   // Matches 0, "", null, undefined, NaN, false.
  a || (a = "default"); // Matches 0, "", null, undefined, NaN, false.

  if (b == null) { b = "default"; } // Matches null, undefined.

  if (typeof c === "undefined") { c = "default"; } // Matches undefined.
}

The falsy default used with variable a is, for example, used extensively in Backbone.js.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Matt Montag
  • 5,911
  • 7
  • 37
  • 45
5

With ES2015/ES6 you can take advantage of Object.assign which can replace $.extend() or _.defaults()

function myFunc(requiredArg, options = {}) {
  const defaults = {
    message: 'Hello',
    color: 'red',
    importance: 1
  };

  const settings = Object.assign({}, defaults, options);

  // do stuff
}

You can also use defaults arguments like this

function myFunc(requiredArg, { message: 'Hello', color: 'red', importance: 1 } = {}) {
  // do stuff
}
Yann Bertrand
  • 2,983
  • 1
  • 19
  • 37
  • In future, you will be able to write this even shorter with object spreading (currently NOT supported by Edge!) - demonstration fiddle: https://jsfiddle.net/L7evm21q/ basic code: `function test(options) { options = { someDefaultParam: '', ...options }; /* do stuff */ }` future ref link: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax#Browser_compatibility – jave.web Oct 17 '19 at 20:06
3

If you're using the Underscore library (you should, it's an awesome library):

_.defaults(optionalArg, 'defaultValue');
roo2
  • 5,571
  • 2
  • 28
  • 44
2

I don't know why @Paul's reply is downvoted, but the validation against null is a good choice. Maybe a more affirmative example will make better sense:

In JavaScript a missed parameter is like a declared variable that is not initialized (just var a1;). And the equality operator converts the undefined to null, so this works great with both value types and objects, and this is how CoffeeScript handles optional parameters.

function overLoad(p1){
    alert(p1 == null); // Caution, don't use the strict comparison: === won't work.
    alert(typeof p1 === 'undefined');
}

overLoad(); // true, true
overLoad(undefined); // true, true. Yes, undefined is treated as null for equality operator.
overLoad(10); // false, false


function overLoad(p1){
    if (p1 == null) p1 = 'default value goes here...';
    //...
}

Though, there are concerns that for the best semantics is typeof variable === 'undefined' is slightly better. I'm not about to defend this since it's the matter of the underlying API how a function is implemented; it should not interest the API user.

I should also add that here's the only way to physically make sure any argument were missed, using the in operator which unfortunately won't work with the parameter names so have to pass an index of the arguments.

function foo(a, b) {
    // Both a and b will evaluate to undefined when used in an expression
    alert(a); // undefined
    alert(b); // undefined

    alert("0" in arguments); // true
    alert("1" in arguments); // false
}

foo (undefined);
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Arman
  • 4,547
  • 3
  • 30
  • 33
2

The test for undefined is unnecessary and isn't as robust as it could be because, as user568458 pointed out, the solution provided fails if null or false is passed. Users of your API might think false or null would force the method to avoid that parameter.

function PaulDixonSolution(required, optionalArg){
   optionalArg = (typeof optionalArg === "undefined") ? "defaultValue" : optionalArg;
   console.log(optionalArg);
};
PaulDixonSolution("required");
PaulDixonSolution("required", "provided");
PaulDixonSolution("required", null);
PaulDixonSolution("required", false);

The result is:

defaultValue
provided
null
false

Those last two are potentially bad. Instead try:

function bulletproof(required, optionalArg){
   optionalArg = optionalArg ? optionalArg : "defaultValue";;
   console.log(optionalArg);
};
bulletproof("required");
bulletproof("required", "provided");
bulletproof("required", null);
bulletproof("required", false);

Which results in:

defaultValue
provided
defaultValue
defaultValue

The only scenario where this isn't optimal is when you actually have optional parameters that are meant to be booleans or intentional null.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
slartibartfast
  • 464
  • 4
  • 8
2

I tried some options mentioned in here and performance tested them. At this moment the logicalor seems to be the fastest. Although this is subject of change over time (different JavaScript engine versions).

These are my results (Microsoft Edge 20.10240.16384.0):

Function executed            Operations/sec     Statistics
TypeofFunction('test');          92,169,505     ±1.55%   9% slower
SwitchFuntion('test');            2,904,685     ±2.91%  97% slower
ObjectFunction({param1: 'test'});   924,753     ±1.71%  99% slower
LogicalOrFunction('test');      101,205,173     ±0.92%     fastest
TypeofFunction2('test');         35,636,836     ±0.59%  65% slower

This performance test can be easily replicated on: http://jsperf.com/optional-parameters-typeof-vs-switch/2

This is the code of the test:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script>
    Benchmark.prototype.setup = function() {
        function TypeofFunction(param1, optParam1, optParam2, optParam3) {
            optParam1 = (typeof optParam1 === "undefined") ? "Some default" : optParam1;
            optParam2 = (typeof optParam2 === "undefined") ? "Another default" : optParam2;
            optParam3 = (typeof optParam3 === "undefined") ? "Some other default" : optParam3;
        }

        function TypeofFunction2(param1, optParam1, optParam2, optParam3) {
            optParam1 = defaultValue(optParam1, "Some default");
            optParam2 = defaultValue(optParam2, "Another default");
            optParam3 = defaultValue(optParam3, "Some other default");
        }

        function defaultValue(variable, defaultValue) {
            return (typeof variable !== 'undefined') ? (variable) : (defaultValue);
        }

        function SwitchFuntion(param1, optParam1, optParam2, optParam3) {
            switch (arguments.length - 1) { // <-- 1 is number of required arguments
                case 0:
                    optParam1 = 'Some default';
                case 1:
                    optParam2 = 'Another default';
                case 2:
                    optParam3 = 'Some other default';
            }
        }

        function ObjectFunction(args) {
            var defaults = {
                optParam1: 'Some default',
                optParam2: 'Another default',
                optParam3: 'Some other default'
            }
            args = $.extend({}, defaults, args);
        }

        function LogicalOrFunction(param1, optParam1, optParam2, optParam3) {
            optParam1 || (optParam1 = 'Some default');
            optParam2 || (optParam1 = 'Another default');
            optParam3 || (optParam1 = 'Some other default');
        }
    };
</script>
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
JDC
  • 1,209
  • 13
  • 30
2

Landed to this question, searching for default parameters in EcmaScript 2015, thus just mentioning...

With ES6 we can do default parameters:

function doSomething(optionalParam = "defaultValue"){
    console.log(optionalParam);//not required to check for falsy values
}

doSomething(); //"defaultValue"
doSomething("myvalue"); //"myvalue"
Kulbhushan Singh
  • 536
  • 5
  • 18
2

During a project I noticed I was repeating myself too much with the optional parameters and settings, so I made a class that handles the type checking and assigns a default value which results in neat and readable code. See example and let me know if this works for you.

var myCar           = new Car('VW', {gearbox:'automatic', options:['radio', 'airbags 2x']});
var myOtherCar      = new Car('Toyota');

function Car(brand, settings) {
    this.brand      = brand;

    // readable and adjustable code
    settings        = DefaultValue.object(settings, {});
    this.wheels     = DefaultValue.number(settings.wheels, 4);
    this.hasBreaks  = DefaultValue.bool(settings.hasBreaks, true);
    this.gearbox    = DefaultValue.string(settings.gearbox, 'manual');
    this.options    = DefaultValue.array(settings.options, []);

    // instead of doing this the hard way
    settings        = settings || {};
    this.wheels     = (!isNaN(settings.wheels)) ? settings.wheels : 4;
    this.hasBreaks  = (typeof settings.hasBreaks !== 'undefined') ? (settings.hasBreaks === true) : true;
    this.gearbox    = (typeof settings.gearbox === 'string') ? settings.gearbox : 'manual';
    this.options    = (typeof settings.options !== 'undefined' && Array.isArray(settings.options)) ? settings.options : [];
}

Using this class:

(function(ns) {

    var DefaultValue = {

        object: function(input, defaultValue) {
            if (typeof defaultValue !== 'object') throw new Error('invalid defaultValue type');
            return (typeof input !== 'undefined') ? input : defaultValue;
        },

        bool: function(input, defaultValue) {
            if (typeof defaultValue !== 'boolean') throw new Error('invalid defaultValue type');
            return (typeof input !== 'undefined') ? (input === true) : defaultValue;
        },

        number: function(input, defaultValue) {
            if (isNaN(defaultValue)) throw new Error('invalid defaultValue type');
            return (typeof input !== 'undefined' && !isNaN(input)) ? parseFloat(input) : defaultValue;
        },

        // wrap the input in an array if it is not undefined and not an array, for your convenience
        array: function(input, defaultValue) {
            if (typeof defaultValue === 'undefined') throw new Error('invalid defaultValue type');
            return (typeof input !== 'undefined') ? (Array.isArray(input) ? input : [input]) : defaultValue;
        },

        string: function(input, defaultValue) {
            if (typeof defaultValue !== 'string') throw new Error('invalid defaultValue type');
            return (typeof input === 'string') ? input : defaultValue;
        },

    };

    ns.DefaultValue = DefaultValue;

}(this));
  • I like that and I'll go similar way. (My only parameter is and object with up to 20 props were maybe 7 are very important). Actually its not only redable and maintainable, it is also reusable and extendable (f.e. adding callback/emit something). Its very clear, thank you for that. – Falk Jul 13 '18 at 17:34
1

This is what I ended up with:

function WhoLikesCake(options) {
  options = options || {};
  var defaultOptions = {
    a : options.a || "Huh?",
    b : options.b || "I don't like cake."
  }
  console.log('a: ' + defaultOptions.b + ' - b: ' + defaultOptions.b);

  // Do more stuff here ...
}

Called like this:

WhoLikesCake({ b : "I do" });
NinjaFart
  • 1,549
  • 1
  • 15
  • 19
1

Folks -

After looking at these and other solutions, I tried a number of them out using a snippet of code originally from W3Schools as a base. You can find what works in the following. Each of the items commented out work as well and are that way to allow you to experiment simply by removing individual comments. To be clear, it is the "eyecolor" parameter that is not being defined.

function person(firstname, lastname, age, eyecolor)
{
this.firstname = firstname;
this.lastname = lastname;
this.age = age;
this.eyecolor = eyecolor;
// if(null==eyecolor)
//   this.eyecolor = "unknown1";
//if(typeof(eyecolor)==='undefined') 
//   this.eyecolor = "unknown2";
// if(!eyecolor)
//   this.eyecolor = "unknown3";
this.eyecolor = this.eyecolor || "unknown4";
}

var myFather = new person("John", "Doe", 60);
var myMother = new person("Sally", "Rally", 48, "green");

var elem = document.getElementById("demo");
elem.innerHTML = "My father " +
              myFather.firstname + " " +
              myFather.lastname + " is " +
              myFather.age + " with " +
              myFather.eyecolor + " eyes.<br/>" +
              "My mother " +
              myMother.firstname + " " +
              myMother.lastname + " is " +
              myMother.age + " with " +
              myMother.eyecolor + " eyes."; 
Mark Funk
  • 11
  • 1
1
function Default(variable, new_value)
{
    if(new_value === undefined) { return (variable === undefined) ? null : variable; }
    return (variable === undefined) ? new_value : variable;
}

var a = 2, b = "hello", c = true, d;

var test = Default(a, 0),
test2 = Default(b, "Hi"),
test3 = Default(c, false),
test4 = Default(d, "Hello world");

window.alert(test + "\n" + test2 + "\n" + test3 + "\n" + test4);

http://jsfiddle.net/mq60hqrf/

Imagine Breaker
  • 1,884
  • 1
  • 10
  • 8
1

Here is my solution. With this you can leave any parameter you want. The order of the optional parameters is not important and you can add custom validation.

function YourFunction(optionalArguments) {
            //var scope = this;

            //set the defaults
            var _value1 = 'defaultValue1';
            var _value2 = 'defaultValue2';
            var _value3 = null;
            var _value4 = false;

            //check the optional arguments if they are set to override defaults...
            if (typeof optionalArguments !== 'undefined') {

                if (typeof optionalArguments.param1 !== 'undefined')
                    _value1 = optionalArguments.param1;

                if (typeof optionalArguments.param2 !== 'undefined')
                    _value2 = optionalArguments.param2;

                if (typeof optionalArguments.param3 !== 'undefined')
                    _value3 = optionalArguments.param3;

                if (typeof optionalArguments.param4 !== 'undefined')
                    //use custom parameter validation if needed, in this case for javascript boolean
                   _value4 = (optionalArguments.param4 === true || optionalArguments.param4 === 'true');
            }

            console.log('value summary of function call:');
            console.log('value1: ' + _value1);
            console.log('value2: ' + _value2);
            console.log('value3: ' + _value3);
            console.log('value4: ' + _value4);
            console.log('');
        }


        //call your function in any way you want. You can leave parameters. Order is not important. Here some examples:
        YourFunction({
            param1: 'yourGivenValue1',
            param2: 'yourGivenValue2',
            param3: 'yourGivenValue3',
            param4: true,
        });

        //order is not important
        YourFunction({
            param4: false,
            param1: 'yourGivenValue1',
            param2: 'yourGivenValue2',
        });

        //uses all default values
        YourFunction();

        //keeps value4 false, because not a valid value is given
        YourFunction({
            param4: 'not a valid bool'
        });
Duco L
  • 279
  • 3
  • 4
1
  1. arg || 'default' is a great way and works for 90% of cases

  2. It fails when you need to pass values that might be 'falsy'

    • false
    • 0
    • NaN
    • ""

    For these cases you will need to be a bit more verbose and check for undefined

  3. Also be careful when you have optional arguments first, you have to be aware of the types of all of your arguments

mcfedr
  • 7,023
  • 3
  • 29
  • 27
1

In all cases where optionalArg is falsy you will end up with defaultValue.

function myFunc(requiredArg, optionalArg) {
    optionalArg = optionalArg || 'defaultValue';
    console.log(optionalArg);
    // Do stuff
}
myFunc(requiredArg);
myFunc(requiredArg, null);
myFunc(requiredArg, undefined);
myFunc(requiredArg, "");
myFunc(requiredArg, 0);
myFunc(requiredArg, false);

All of the above log defaultValue, because all of 6 are falsy. In case 4, 5, 6 you might not be interested to set optionalArg as defaultValue, but it sets since they are falsy.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
0

Correct me if I'm wrong, but this seems like the simplest way (for one argument, anyway):

function myFunction(Required,Optional)
{
    if (arguments.length<2) Optional = "Default";
    //Your code
}
Brian McCutchon
  • 7,738
  • 3
  • 27
  • 42
0

Those ones are shorter than the typeof operator version.

function foo(a, b) {
    a !== undefined || (a = 'defaultA');
    if(b === undefined) b = 'defaultB';
    ...
}
Aurélien Ooms
  • 4,834
  • 3
  • 17
  • 28
-1

I suggest you to use ArgueJS this way:

function myFunc(){
  arguments = __({requiredArg: undefined, optionalArg: [undefined: 'defaultValue'})

  //do stuff, using arguments.requiredArg and arguments.optionalArg
  //    to access your arguments

}

You can also replace undefined by the type of the argument you expect to receive, like this:

function myFunc(){
  arguments = __({requiredArg: Number, optionalArg: [String: 'defaultValue'})

  //do stuff, using arguments.requiredArg and arguments.optionalArg
  //    to access your arguments

}
zVictor
  • 3,288
  • 3
  • 35
  • 52
-1

It seems that the safest way - to deal with all \ any falsy types of supplied arguments before deciding to use the default - is to check for the existence\presence of the optional argument in the invoked function.

Relying on the arguments object member creation which doesn't even get created if the argument is missing, regardless of the fact that it might be declared, we can write your function like this:

  function myFunc(requiredArg, optionalArg){
        optionalArg = 1 in arguments ? optionalArg : 'defaultValue';
  //do stuff
  }

Utilizing this behavior: We can safely check for any missing values on arguments list arbitrarily and explicitly whenever we need to make sure the function gets a certain value required in its procedure.

In the following demo code we will deliberately put a typeless and valueless undefined as a default value to be able to determine whether it might fail on falsy argument values, such as 0 false etc., or if it behaves as expected.

function argCheck( arg1, arg2, arg3 ){

       arg1 = 0 in arguments || undefined;
       arg2 = 1 in arguments || false;
       arg3 = 2 in arguments || 0;
   var arg4 = 3 in arguments || null;

   console.log( arg1, arg2, arg3, arg4 ) 
}

Now, checking few falsy argument-values to see if their presence is correctly detected and therefore evaluates to true:

argCheck( "", 0, false, null );
>> true true true true

Which means -they didn't fail the recognition of/as expected argument values. Here we have a check with all arguments missing, which according to our algo should acquire their default values even if they're falsy.

argCheck( );
>> undefined false 0 null

As we can see, the arguments arg1, arg2, arg3 and the undeclared arg4, are returning their exact default values, as ordered. Because we've now made sure that it works, we can rewrite the function which will actually be able to use them as in the first example by using: either if or a ternary condition.

On functions that have more than one optional argument, - a loop through, might have saved us some bits. But since argument names don't get initialized if their values are not supplied, we cannot access them by names anymore even if we've programmatically written a default value, we can only access them by arguments[index] which useless code readability wise.

But aside from this inconvenience, which in certain coding situations might be fully acceptable, there's another unaccounted problem for multiple and arbitrary number of argument defaults. Which may and should be considered a bug, as we can no longer skip arguments, as we once might have been able to, without giving a value, in a syntax such as:

argCheck("a",,22,{});

because it will throw! Which makes it impossible for us to substitute our argument with a specific falsy type of our desired default value. Which is stupid, since the arguments object is an array-like object and is expected to support this syntax and convention as is, natively or by default!

Because of this shortsighted decision we can no longer hope to write a function like this:

function argCheck( ) {
    var _default = [undefined, 0, false, null ],
        _arg = arguments;

 for( var x in _default ) {
         x in _arg ? 1 : _arg[x] = _default[x];
        }
    console.log( _arg[0],_arg[1],_arg[2],_arg[3] );
}

in which case, we would be able to write each default value of a desired type in arguments row and be able to at least access them by args.index.

For instance this function call would yield:

argCheck();
>>undefined 0 false null

as defined in our default array of arguments values. However the following is still possible:

argCheck({})
>>Object {  } 0 false null

argCheck({}, [])
>>Object {  } Array [  ] false null

But regretfully not:

 argCheck("a",,,22);
 >>SyntaxError: expected expression, got ','

Which would otherwise be logging:

>>a 0 false 22

but that's in a better world! However - for the original question - the topmost function will do just fine. e.g.:

function argCheck( arg, opt ) {
         1 in arguments ? 1 : opt = "default";
         console.log( arg, opt );
}

p.s.: sorry for not preserving the types of chosen defaults in my argument inputs while writing them.

Bekim Bacaj
  • 4,530
  • 1
  • 19
  • 25
  • A JavaScript illiterate has just down-voted the best and the most complete answer on the issue without even knowing why. Maybe because it is to elaborate and got lost in the process. Better luck next time, with your reading and comprehension abilities. :) – Bekim Bacaj Sep 08 '17 at 09:31
  • There's many reasons to downvote and no one owes you an explanation as to why they did so. Don't take it too personal, it's non-constructive and a bad look – nicholaswmin Dec 02 '17 at 06:40
  • The main reason out of "many reasons" - in this case - is being a radical JavaScript ignorant - As about your unapparent false remark that no one owes an explanation for an occasionally 'stupid' downvote, is incorrect - because as far as I remember from the first time I felt I had to downvote, the SO policy required / instructed me to also give an explanation for the downvote. – Bekim Bacaj Dec 02 '17 at 16:04
  • Misusing big words doesn't take away the fact that in more than one of your other answers you get the exact same response as I gave you. You might be better off taking it as constructive criticism the next time around. If everyone looks ignorant but you, perhaps it is you who might be the ignorant. – nicholaswmin Dec 02 '17 at 16:14
  • @NicholasKyriakides where is that constructive criticism because there is none. Downvote is not a criticism - it is a punishment without explanation and it may be simply because of the color of my skin. – Bekim Bacaj Dec 02 '17 at 16:16
  • `it may be simply because of the color of my skin` - I can almost guarantee you the community is not like that at all. Be nicer when asking for comments on down votes and someone will give it to you is all I'm saying. – nicholaswmin Dec 02 '17 at 16:19
  • The community is not like that, but it is made out of individuals who never knew each other. -I was being very nice, and yet - everybody knows that Greeks hate Albanians. :) You'll have to point to my error for an honest and constructive downvote that everybody would benefit from. Otherwise, downvoting a qualitative answer, is a malicious act and against the community interests. – Bekim Bacaj Dec 02 '17 at 16:36
-2
function foo(requiredArg){
  if(arguments.length>1) var optionalArg = arguments[1];
}
Dustin Poissant
  • 2,710
  • 1
  • 17
  • 22
  • 2
    You might want to fix that typo and add an explanation for what you're recommending here. – Shog9 Apr 09 '14 at 19:00
  • I don't think this needs much explanation, it simply answers the question. There are many ways of accomplishing "optional function parameters" in JavaScript. I have seen 3 or 4 other good answers here, but I have not seen this answer given, so I gave it. It may not be the simplest or most straightforward answer but it does work. – Dustin Poissant Apr 10 '14 at 19:51
  • This is the same as Roenving's answer, but doesn't provide a default value. That said, I quite like the readability of defining optional args separately to required ones: if that's the purpose of your answer, it'd help to say so – user56reinstatemonica8 Jan 01 '15 at 23:43
  • I do not think my answer is by any means the best. I rather prefer angelcool.net's answer. I was simply listing that this is another option. I would never use this method, I just thought the asker would prefer to have all available options proposed and they can choose for themselves which method they like best, and I noticed this answer was not given, and so in order to try and provide the asker with the most complete answer I felt this option (though it sucks) should be given. – Dustin Poissant Jan 08 '15 at 19:24