Named function arguments in JavaScript
OK, there are no such things as ‘named function arguments’ in JavaScript, but I’ve gotten into the habit of using a particular pattern and I’m liking it. So I thought I’d share.
This one weird trick is nothing more than combining shorthand property names, destructuring assignment, and passing a single object argument. If you’re not familiar with some of those, read on!
Passing in options
I have a function that takes a mouse event and returns the x and y coordinates for that event. It looks like this:
Fairly basic stuff. Now imagine that sometimes I want to ‘snap’ the results to some grid. I just pass in another argument.
Still nothing of note going on. But wait, now developer #2 comes along and sees getNormalMouseEvent(e, 10), and they don’t know what the 10 does. Sure they can go and look it up, but it will slow them down. It’s like if you’re hunting a gazelle and you have to stop and do up your shoelace; maybe it doesn’t take that long, but it might be long enough for the gazelle to get away and then you’ll have to go home to your hungry tribe with takeaway Chinese and they will know you have failed.
But if we make just a tiny change to the syntax (lines 1 and 18)…
Now our ‘10’ has a name.
- We’re passing a single object rather than two discrete arguments.
- We’ve added some curly braces when calling the function.
- We pass e in just the same. This takes advantage of ES2015 object initialization shorthand. That means that if your property name is the same as the name of the variable that holds the value, then you only need one. So {e} is the same as {e:e}.
- We pass in snap: 10 as a key/value pair.
- In the function definition all we need to do is add some curly braces around the parameters. This takes advantage of ES2015 object destructuring syntax. Here’s how it maps to ES2009*.
End of example one.
Promises
In this next scenario, I want to sign a user in. If they’ve signed in before, I’ll say welcome back. If this is the first time they have signed in, I’ll create a user account and give them the red carpet treatment.
Each step in the sign in process is asynchronous so I’m using promises, and as you may know Promise.resolve() can only be passed one value. So let’s pass an object and use destructuring to make it nice and readable.
Line 19 is a bit heavy on the curves and curlies, but you adjust.
End of example two.
Returning something unintuitive
Next up, a less common scenario. And one that requires a little explaining.
I’m currently writing a web app for developers to store the text for their websites (go, use it). A user can have ‘projects’ and in each project, many ‘screens’. I have a function that adds a new project and also adds a new screen to get the user started. When a new project is created, the user is navigated to that new project, but specifically to the new screen that was created inside that project.
So I need a function that adds a new project but returns the ID of the new screen that was created. It would be weird if a function called ‘addProject’ just returned the ID of a screen. So instead, I have something like this:
The two interesting parts are the object returned on line 17 and the way we get the new screen ID on line 21. It’s a subtle difference but it means that developer #2 couldn’t accidentally think they were getting the project ID back from this function, since they need to name which property they want back (in this case the returned object only has one property: newScreenId, but I could just as easily also return the newProjectId).
End of example three.
Thanks for reading!
* Some of you may still be calling ES2009 by its old name, ‘ES5’. You need to pull your socks up. ES2017 will probably be called ‘dolphin’ in which case you will be two versioning schemes behind and confused when people start referring to ES2015 as ‘eagle-hawk’.