In Summary: While you may have hesitations about using an object, it's worth noting that modern JavaScript engines are incredibly efficient at creating and disposing of objects quickly. With the added benefits of parameter defaults and parameter destructuring, utilizing an options object seems to be the most optimal solution for your scenario. Refer to the section on "Notes on passing in an object (defaults, destructuring)" below for more information.
You've explored two primary options so far (I'll provide insights on the object-passing version). Another approach involves a variation of the builder pattern, though it also necessitates the use of an object. While you've expressed reluctance towards this method, it's essential to consider that modern JavaScript engines handle object creation and disposal with exceptional speed, addressing any concerns you may have.
Using Marker Strings
An alternative option came to mind after reviewing Bhushan Babar's append/prepend suggestion: Instead of following that route, you could integrate marker strings into the arguments list to signify the subsequent argument, such as:
showNotification("the required parameter", "a", value_for_a, "c", value_for_c);
While this approach initially appears to bypass object creation, executing it will actually result in the generation of an object peculiar to modern JavaScript engines: arguments
, which stores passed-in arguments as a pseudo-array. This is the only feasible way to manage such input, alongside a rest parameter, which likewise generates an object.
Alternative Builder Pattern
In this strategy, the main function returns a builder object outfitted with setters for different options, culminating in a final call signaling readiness to proceed (whereas the typical builder pattern triggers the construction of the final object). Application of this concept would resemble the following:
showNotification("the required param")
.withA(value_for_a)
.withC(value_for_c)
.go();
While implementing this scheme may seem intricate compared to other methods, it is not inherently challenging.
Insights on Object-Based Implementation (Including Defaults and Destructuring)
If you opt for employing an object (despite reservations), default parameters and destructuring can enhance the object's usability significantly:
let showNotification = function({a = 1, b = 2, c = 3, d = 4, e = 5, f = 6} = {/*default if no object at all*/a: "foo"}){
console.log(a,b,c,d,e,f);
};
showNotification();
showNotification({});
showNotification({a:42});
In one of your comments, you mentioned:
Here, all parameters are optional, except the first one.
This suggests that you likely require the initial parameter along with an options object:
let showNotification = function(firstThing, {a = "default_a", b = "default_b"/*etc.*/} = {}) {
console.log(firstThing, a, b);
};