Modern JavaScript now has Array.prototype.flat() which will do the trick.
let a = "a";
let b = "b";
[a].flat(); // result: ["a"]
[[a, b]].flat(); // result ["a", "b"]
This allows you to do this in your function:
function acceptsArrayOrScalar(arrayOrScalar){
return [arrayOrScalar].flat();
}
acceptsArrayOrScalar(a); // returns [a]
acceptsArrayOrScalar([a, b]); // returns [a, b]
This kind of thing is useful if you want to be able to iterate over your parameter with a for..of or forEach and you don't want to have to do a manual check of isArray() etc.
function doStuff(param){
[param].flat().forEach(x => console.log(x));
}
doStuff("a"); // logs "a"
doStuff(["a", "b"]); // logs "a" and then "b"
In the contrived example above, you could probably achieve a similar result with the ...rest parameter if all you care about is being able to handle a variable amount of parameters:
function doMoreStuff(...param){
param.forEach(x => console.log(x));
}
Note though that in this last example, we're not accepting a scalar or an array, we're accepting a variable number of arguments, so it's a slightly different signature, but it might be just what you need.
doMoreStuff("a"); // logs "a"
doMoreStuff("a", "b"); // logs "a" and then logs "b"
doMoreStuff(["a", "b"]); // maybe not what we want: logs ["a", "b"]
And if you want real versatility where you can accept a scalar, or an array, or a variable number of scalars, you could specify the depth parameter:
function doAllTheStuff(...params){
[params].flat(2).forEach(x => console.log(x));
}
doAllTheStuff("a"); // logs "a"
doAllTheStuff(["a", "b"]); // logs "a" and then "b"
doAllTheStuff("a", "b", "c"); // logs "a", then "b", then "c"
...and even...
doAllTheStuff(["a", "b"], "c"); // logs "a", then "b", then "c"
Arguably, the Array.isArray() ternary is computationally faster, it's unlikely that any production code that uses this trick will suffer significantly, but just be aware of that nuance if inside a game loop or something that needs to be highly performant.