In this week’s selection, the JavaScript Patterns book continues into its interesting deep dive on the intracacies of how the language works, looking at functions, or the blocks of code that can actually do something. JS has some quirks everywhere, but particularly in this area, and I think functions and how they work have a lot to do with a common perception of JS as a harder, and more, well, different language.
I was delighted of course to be reminded that a function is an object, like most things in JS are. But I had not, for example, thought of a function as having a name property you can call on with what you call the function. Thus making an anonymous function literally one without a name property. That name property is not standard, though, the book cautions, so it’s not something we can totally rely on for cross-browser compatibility. But I could see it being helpful in some contexts for debugging, as long as the programmer wasn’t depending on it in production.
The book gives some good reasons for using anonymous vs. named functions in various contexts. These days, as part of cleaning up my code, I realize I often use a third pattern — assigning an anonymous function as a member of an object. It doesn’t itself has a name, but is assigned to a variable that has a name.
The concept of hoisting, or (as I understand it), the computer reading through code, grabbing ahold of all of it and moving functions to top of the code, allows you to call a function above where it is defined in the code. This seems relatively unique to JS. I never really understood why such things were possible, I would have expected breakage in that concept. Or, if this works in JS, I would have expected it to work in Ruby, too. But, it doesn’t. It’s nice to know why this is happening, but I think for best practices, it enhances readability to define what you are calling before you actually go ahead and call it.
Callbacks and timeouts were discussed. I’m much more ready for this section than I would have been a year ago, and more ready then than a few years prior. This is the concept of waiting for certain code to complete before running the next block. For example, if switching what text is visible, we first fade out current text, then only when that is completed, fade in the new text. A callback says only run the second block of code once the first is done, whether that takes half a second or 30 seconds.
This is the opposite, to me anyway, of a timeout, which relies on waiting a certain amount of time (5 seconds) and running the second block. The first block could have finished awhile ago, or still be in process. It’s more dependable, from what I’ve learned, to test on the functionality of what’s going on, not the time. Otherwise, one function may execute too early, and then we have what is called a “race condition” where two bits of code are racing each other to completion. Before I understood this, I had strange timing errors I didn’t understand all of the time.
Memoization is a concept that has to do with storing properties on the function, instead of calculating them dynamically on the fly. I could see this being very helpful for performance reasons, if calculating certain objects or parts of the code was taking too long when something is called repeatedly.
Currying, or only passing some arguments to a function, was the most complicated concept to me, and I’ll admit it’s not totally clear. But what I did get out of this is you can associate certain defaults with a function, and functions can be more flexible when you only use one part of them at once. I worry this concept could make readability more difficult, if someone (or even the you of the future) is trying to remember how your code works. And I’m still trying to think of a good example where the flexibility provided by currying is worth the potential confusion vs. breaking out separate functions for the same use case.