- Declaring optional function parameters in JavaScript
- Table of Contents
- What are Optional Parameters?
- How Optional Parameters work?
- Where is it most useful?
- Code
- Default function parameters
- Using undefined property
- Using arguments variable
- Using the Logical OR operator (‘||’)
- Caveats & References
- Optional parameters and decorators in JavaScript
- Using a decorator
Declaring optional function parameters in JavaScript
We continue with Flexiple’s tutorial series to explain the code and concept behind common use cases. In today’s article, let’s take a dive into how Optional Parameters in JavaScript can be implemented and also understand where exactly using them would prove to be most useful.
Table of Contents
What are Optional Parameters?
By definition, an Optional Parameter is a handy feature that enables programmers to pass less number of parameters to a function and assign a default value.
Firstly, let us first understand what the word Optional Parameter means. Parameters are the names listed in the function definition. They are used to define a function and are also called formal parameters and formal arguments. In the following example, parameter1 and parameter2 are parameters of the ‘exampleFunction’ function.
function exampleFunction(parameter1, parameter2) < //code >
In this context, Optional Parameters are those parameters that need not always be passed i.e. they’re optional. The next obvious question would be «What value is passed when you don’t pass a parameter?». So let’s answer that in our next section.
Before moving ahead, if you find anything difficult , do checkout other Flexiple tech blogs where we cover various basic JS concepts and breaking them down so that they can be easily consumed.
How Optional Parameters work?
Usually, when you don’t pass parameters, ‘undefined’ is passed instead. But using Optional Parameters, you can define a default value. So, whenever no value or undefined is passed, a default value is passed in its place.
Before we look at different ways to implement Optional Parameters in JavaScript, let’s first see where we would need them.
Where is it most useful?
Optional parameters are great for simplifying code, and hiding advanced but not-often-used functionality. If majority of the time you are calling a function using the same values for some parameters, you should try making those parameters optional to avoid repetition.
For example, assume you are using a function to perform a google search. This function accepts the following parameters
Parameter 1: searchEngineURL
Parameter 2: searchString
Now, because you always use Google search engine, you could assign a default value to the Parameter1 as Google’s URL and not always pass this URL and only pass searchString each time you call the function. Hence the searchEngineURL is the optional parameter.
Code
Default function parameters
In this method, you can initialize named parameters with default values whenever no value or undefined is passed.
function add(a, b = 1) < return a + b; >console.log(add(1, 2)); // expected output: 3 console.log(add(1)); // expected output: 2
Using undefined property
Whenever no value or undefined is passed to a function, a conditional (IF) statement could be used to pass the default value instead if any of the parameters is undefined.
//optional parameters JavaScript-Using undefined property function add(a, b) < if (a === undefined) < a = 1; >if (b === undefined) < b = 1; >return a + b; > console.log(add(1, 2)); // expected output: 3 console.log(add(1)); // expected output: 2
Using arguments variable
JavaScript functions have a built-in object called arguments. It contains an array of parameters. The length of this array gives the number of parameters passed. A conditional statement is used to check the number of parameters passed and pass default values in place of the undefined parameters.
//optional parameters Javascript-Using arguments variable function add(a, b) < if (arguments.length == 0) // Means no parameters are passed < a = 1; b = 2; >if (arguments.length == 1) // Means second parameter is not passed < b = 2; >return a + b; > console.log(add(5, 10)); // expected output: 15 console.log(add(5)); // expected output: 7
Using the Logical OR operator (‘||’)
In this method, the optional parameter is «Logically ORed» with the default value within the body of the function. In the example below, if the value of b is undefined, 2 is passed instead.
//optional parameters Javascript-Using the Logical OR operator (‘||’) function add(a, b) < var b1 = b || 2; return a + b1; >add(5, 10); // expected output: 15 add(5); // expected output: 7
Caveats & References
- Checkout MDN’s JavaScript default parameters doc for more nuances & limitations
- ECMAScript 2015 allows default parameter values in the function declaration
Optional parameters and decorators in JavaScript
Optional parameters is a widely used programming pattern and is available by default in many languages. For example, an example in Python could be:
def my_function(required_parameter, optional_parameter=None): print(optional_parameter) # will be None if not passed
It is easy enough with most languages, but when it comes to Javascript, an issue we have is that the last parameter is usually used for the callback, so a lot of functions look like
function (requiredParameter, optionalParameter, callback) >
so the callback can be either the second or the third parameter, depending wether the optional parameter is provided or not. There are a lot of ways to check if the optional parameter is present, assign it a default value if not, and assign the callback to the right argument.
The simplest way to do this could be:
function (requiredParameter, optionalParameter, callback) if (arguments.length 2) callback = optionalParameter; optionalParameter = <>; // default value > >
Another common way is to use a real array for the arguments:
function(err, optionalA, optionalB, callback) var args = []; for (var i = 0; i arguments.length; i++) args.push(arguments[i]); > err = args.shift(); callback = args.pop(); if (args.length > 0) optionalA = args.shift(); else optionalA = <>; // default value if (args.length > 0) optionalB = args.shift(); else optionalB = <>; // default value >
This can become a mess quite easily and is too repetitive.
Using a decorator
There are many solutions to come over this lack of DRYness and have things working more easily. Some libraries take the arguments of the function and wrap it in an easy to use object.
Here, I am going to present a solution using a decorator, which have the advantage that the functions can be written just as always, without having to check for the parameters anymore.
We are here going to write a function which has the following behavior:
- The first argument is the number of required arguments of the function
- The last argument is the function to decorate
- The arguments in between are the default values for the optional parameters
- The return value is the decorated function
For example, we should get the following result:
var myFunction = wrapIt(1, "default", <>, function (requiredParameter, optionalString, optionalObject, callback) console.log(requiredParameter); console.log(optionalString); console.log(optionalObject); if (callback) callback(); >); var callback = function () console.log("calling callback"); >; myFunction("req", callback); // will print: // req // default // <> // calling callback myFunction("req", "mystring", callback); // will print: // req // mystring // <> // calling callback myFunction("req", "mystring", a: 1>, callback); // will print: // req // mystring // // calling callback
We are now going to implement this decorator. Let’s start with a decorator that just call its last argument, without any modifications to the arguments.
var wrapIt = function () var baseArgs = []; baseArgs.push.apply(baseArgs, arguments); // transform the arguments into an array var decorated = baseArgs.pop(); return function () return decorated.apply(this, arguments); >; >;
This function can be called as the one provided in the above example, but will not modify the arguments. We now need to transform the arguments to leave the required parameters as are, and then assign the defaults values if the optional parameters are not present.
var wrapIt = function () var baseArgs = []; baseArgs.push.apply(baseArgs, arguments); // transform the arguments into an array var requiredArgsCount = baseArgs.shift(); var decorated = baseArgs.pop(); return function () if (arguments.length requiredArgsCount) return decorated.apply(this, arguments); > return decorated.apply(this, arguments); >; >;
Here, we get the number of required arguemnts in the first parameter, and then leave only the default values for optional parameters in baseArgs . When the required arguments are not provided, the behavior is not predictable, so we just call the function without further processing. Finally, we just need to build the array for the decorated function arguments with either the provided parameter or with the default value.
var wrapIt = function () var baseArgs = []; baseArgs.push.apply(baseArgs, arguments); var requiredArgsCount = baseArgs.shift(); var decorated = baseArgs.pop(); return function () if (arguments.length requiredArgsCount) return decorated.apply(this, arguments); > var i; var args = []; args.push.apply(args, arguments); var decoratedArgs = []; var cb = null; if (typeof args[args.length - 1] === 'function') cb = args.pop(); > for (i = 0; i requiredArgsCount; i++) decoratedArgs.push(args.shift()); > for (i = 0; i baseArgs.length; i++) if (args[i]) decoratedArgs.push(args[i]); > else decoratedArgs.push(baseArgs[i]); > > decoratedArgs.push(cb); return decorated.apply(this, decoratedArgs); >; >
We extract the last argument, which should be the callback, only if it is a function. Then, we push all the required arguments into the decorated function arguments, we then push the optional arguments or their default value, and finally we push the callback at the end of the array. We then call the decorated function with the built arguments array.
This should work for all the cases in the example above, and provides an easy way to work with optional parameters.