December 24, 2021
In Javascript, functions are defined by name and all function parameters are passed based on position. This means that any parameters not provided in a function call are passed as undefined
and that if there are three parameters you must specify all three values even if you only want to pass the third parameter.
In this post we will look at a technique to provide parameters by name, which provides both flexibility for parameter definition and clarity for which parameters are passed to a function.
The concept of named parameters is available in many languages and provides an expressive way to define the parameters passed to a function. Javascript ECMA5, as implemented by Nashorn, does not provide this capability natively, but thanks to the flexibility of JavaScript Objects and JavaScript Object Notation (JSON), we can implement a close imitation with many of the benefits.
First, let's look at a typical function definition and call. Here we have a function with three parameters and a corresponding call with three values.
function example(param1, param2, param3) {// do things with the parameters}// call the functionexample(value1, value2, value3);
Considering this example, what if we do not want or need to pass the param2
value? Our example would now look like the following, where we still need to pass the second value, explicitly defined as undefined
, in order to pass the third.
function example(param1, param2, param3) {// do things with the parameters// value1 has value of param1var value1 = param1;// value2 is now has a value of undefinedvar value2 = param2;// value3 has value of param3var value3 = param3;}// call the functionexample(value1, undefined, value3);
To transform this to a named parameter function all we need to do is change our function to accept a single parameter and then pass in a JavaScript Object as the value. The parameter values can then be accessed as member properties on the parameter object.
function example(param) {// do things with the parameters// value1 has value of param.value1var value1 = param.param1;// value2 is now has a value of undefinedvar value2 = param.param2;// value3 has value of param.value3var value3 = param.param3;}// call the functionexample({"param1": value1,"param3": value3});
To take this one step further, you can define a new prototype
and constructor
for a parameter named ExampleParam
and then define the default values within the constructor
function. We can also validate that required parameters have been provided and because the param
value is now an object, we can verify that the correct object has been passed in. As a bonus we have also defined a function of getParam4()
on ExampleParam
that returns a concatenation of the param1
and param2
values.
function example(param){if (!param instanceof ExampleParam) {throw new Error("Only ExampleParam objects are allowed as a parameter");}// value1 has value of param.value1var value1 = param.value1;// value2 is now has a string value of "default value"var value2 = param.value2;// value3 has value of param.value3var value3 = param.value3;// value3 is "value1 value3"var value4 = param.getParam4();}example(new ExampleParam({"param1":"value1", "param3":"value3"}));// define the prototype constructor functionfunction ExampleParam(params) {this.param1 = params.param1 ? params.param1 : undefined;// if params.param2 is not provided then set a default value.this.param2 = params.param2 ? params.param2 : "default value";this.param3 = params.param3 ? params.param3 : undefined;if (!this.param3) {throw new Error("param3 is required");}this.getParam4 = function () {return this.param1 + " " + this.param3;}}ExampleParam.prototype.constructor = ExampleParam;
In our calendar invite post, which can be found here, we created a function that had numerous parameters, with the last two being optional. Here we have reworked the function signature to take an InviteParameters
object, which also provides validation of the inputs, ensuring that required parameters are provided, are the correct type and that the start time is before the end time. In the example below the invite is sent with an optional location
value, without having to also provide the optional organizer
value.
SimpleDateFormat = Java.type("java.text.SimpleDateFormat");Date = Java.type("java.util.Date");// call the main function of this script.main()function main() {var f = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");f.setTimeZone(userInfo.getTimeZone());// this is a Date type, from an Mbo you can Mbo.getDate("DATEATTRIBUTE")var startTime = f.parse("2022-01-01T13:00:00Z");var endTime = f.parse("2022-01-01T14:00:00Z");// test the sendInvite function withsendInvite(new InviteParameters({"userInfo": userInfo,"subject": "This is a meeting request","message": "Here are details about our meeting.","startTime": startTime,"endTime": endTime,"location": "Conference Room 4"}));}function sendInvite(inviteParams) {if (!inviteParams instanceof InviteParams) throw new Error("The inviteParams parameter must be an instance of InviteParameters");//... send invite logic here}function InviteParameters(params) {this.userInfo = params.userInfo ? params.UserInfo : undefined;this.from = params.from ? params.from : undefined;this.to = params.to ? params.to : undefined;this.subject = params.subject ? params.from : "Invite from Maximo";this.message = params.message ? params.message : "";this.startTime = params.startTime ? params.startTime : undefined;this.endTime = params.endTime ? params.endTime : undefined;this.organizer = params.organizer ? params.organizer : undefined;this.location = params.location ? params.location : undefined;if (!userInfo) throw new Error("The userInfo parameter is required.");if (!from) throw new Error("The from parameter is required.");if (!to) throw new Error("The to parameter is required.");if (!startTime) throw new Error("The startTime parameter is required.");if (!endTime) throw new Error("The endTime parameter is required.");if (!startTime instanceof Date) throw new Error("The startTime parameter must be an instance of the java.util.Date class.");if (!endTime instanceof Date) throw new Error("The endTime parameter must be an instance of the java.util.Date class.");if (startTime.after(endTime)) throw new Error("The startTime parameter must be before the endTime parameter");}InviteParameters.prototype.constructor = InviteParameters;
In this post we demonstrated using JSON objects to provide named function parameters. We then used an object prototype to define a new constructor that provided validation of the named parameters to provide consistent validation logic. Finally we revisited the sendInvite function and applied named parameters to provide validation and clarity to the function call.
Hopefully you have found this useful and if you have any questions or comments please reach out to us at [email protected]