This course has been updated! We now recommend you take the Deep JavaScript Foundations, v3 course.
Transcript from the "Named Function Expressions" Lesson
[00:00:00]
>> Kyle: Talking about those named function expressions for a moment. Let's dig into that question. If we look at this example, we look at two different ways that a function expression can be created. One is what we would call anonymous function expression. You notice the function keyword on like one followed immediately by the parentheses.
[00:00:19] There's no name identifier. That is by far the most common way that people express named function expression. As a matter of fact, we typically see that most often when we pass a function as a call back to some other function. We see this function keyword immediately followed by the parentheses set.
[00:00:36] And that's referred to as an anonymous function expression. JQuery and other tools in libraries and frameworks that popularize this style. It's also a lot easier because you just type it out, it's almost a default kind of muscle memory, just to type out the word function and put a parentheses.
[00:00:53] On line 5, we see an example of a function expression that we call a named function expression and has a name. And as we just described, that name is actually going to be accessible inside itself, but not in the closing scope. It's okay that we have those same names here.
[00:01:08] Sometimes those names will be different. Sometimes there is an external name that your going to use to refer something. Or there's some control reason why you're assigning it to a property of an object or something. And it needs to be called a certain thing on the outside. But you might have a different and more descriptive name that you wanna use on the inside, and that's entirely okay as well, okay?
[00:01:26] So the question often comes up, should I just create all my functions this way? And as a matter of fact, shouldn't I just do a const here, and say const keyHandler? That's how a lot of people seem to do it. I prefer function declarations as oppose to function expressions.
[00:01:41] My general rule of thumb is if a function is going to have any more then about two or three lines of code I make it into a function declaration almost without question. There is very few exceptions to that. I will sometimes us an inline function expression if there is only one or two lines of code.
[00:01:56] If there is any substantial amount of lines of code I will make it into a function declaration. Function declarations have to have names, so there's no question. There is no such thing as an anonymous function declaration. Actually technically there is with ES6 modules but let's not worry about that.
[00:02:12] Function declarations always have names, okay? But it's this function expression that we should ask about. Because our default, our instinct is to write these anonymous function expressions. Many people like that short in form. In fact with ES6 we added the whole arrow function form to make it even shorter and even more anonymous.
[00:02:30] We'll talk about arrow functions later today. So what's the difference between an anonymous function expression and a named function expression? What I will say is this. You should always, and I don't make very many absolutes, but this is one of them. You should always, with no exceptions, prefer the named function expression over the anonymous function expression.
[00:02:54] Even though it's the harder thing to do. Even though you have to come up with a good name for it. Even though it's a little bit more typing. Even though it's a little bit more verbose. It's always gonna be more preferable and there are main reasons why it's more preferable to put a name on it.
[00:03:07] Let me give you some of the benefits to think about in terms of the why a named function expressions is preferable to an anonymous one. The first one, provides a handy self reference to the functions from inside of itself. This is useful for a variety of things, most notable recursion.
[00:03:24] If you have a function that is going to need to recurs on its self, having a name inside of it's self is useful. If you refer to a function from inside of itself with an identifier that is actually enclosed in the outer scope. Like for example that first one on line 1 of the previous slide where I said var clickHandler.
[00:03:41] If I try to use the name clickHandler inside of that function to refer to itself, that is not actually a reliable self-reference because that variable is in an outer scope that I don't control. And somebody else later might re-assign that variable to point to some different value. So it's not a reliable self-reference.
[00:04:00] Other examples of self-references. I regularly find myself with clickHandlers, with eventHandlers in particular, wanting to unbind the eventHandlers as soon as it fires the first time. Typically the frameworks you work with will want you to provide a reference to the function that was actually bound for the event.
[00:04:18] So having a self-reference is far better than using something like the duplicated arguments .calle or something like that. You wanna have a good self reference if you need to refer to the function object. For example, inspecting its properties if you wanna recurse, if you wanna reference it in an event handler like front binding.
[00:04:37] All of these reasons are reasons why self-references are preferable when they are the name function, when they were the named lexical identifier. And by the way, that identifier in the function expression and the named function expression not only is it reliable in the sense that you control it in the scope, it's also read only.
[00:04:54] You can't reassign that to anything else. So you know for sure inside of that scope that name will always refer to the function itself. As a reliable handy self reference. By the way, even though you may not have an occasion for that right now, sometimes those occasions grow over time.
[00:05:13] And it's better to have a name in place in case you need it even if you aren't gonna need it. The consistency is important. Okay so that's one reason for wanting to have a name on your function expression. The next one, how many of you have ever had an error in your JavaScript program, anybody?
[00:05:31] Okay, good that's a happy occurrence that we're all one happy big family, right? We've all had errors. How many of you have ever seen in a stack trace in your console, anonymous function, anonymous function, over an over again, line after line after line. Anybody seen that? It's super helpful, right?
[00:05:46] Especially in production code, where everything's minified, so they all say line 1, character 32,712. Cuz we all know exactly what that function is, right? Guess what happens if you put a name on your function expressions. It uses the name in your stack trace. Immediately you make your code more debuggable.
[00:06:04] By using those names in the stack traces. And by the way minifiers used to strip out those names. Now the minifiers, like for example uglify.js, at my behest, have an option that allows you to preserve the function name expression even if it's not used to preserve that name expression as written.
[00:06:22] So that your minified production code is still debuggable. Keeping that name expression there makes you code more debuggable and I honestly think that rule, that fact in of itself is more than enough justification. Because we're not not doing happy path driven development here. We wanna write code that is robust to the problems that will happen.
[00:06:44] And even if you can't imagine any scenario by which this function's gonna participate in a stack trace, it's probably going to participate in a stack trace at some point. So it's a good idea to have a good handy name. True story, I literally have actually been able to figure out a problem, knew exactly what my bug was, without even looking at my code.
[00:07:05] Simply looking at the stack trace and seeing the order of function calls. If they both set anonymous, I would had no idea. But when I saw a call b and I was like, wait a minute, b should have called a. I know exactly what's wrong with this. An off by one index or something right?
[00:07:20] So, by knowing for sure what the name is, we can already debug our programs better. And even at worst, we're getting some kind of mental context in which to approach the code. If that name says something like handleClickPresses, you know kind of what happened. There was a key press, there was a click that happened, there was some kind of this that happened.
[00:07:42] That gives me some kind of context and clue as to approach my code. If it just says anonymous function, you're stuck going to look at the rest of the code. The third and final reason, the third and final benefit. I'd argue that this creates more self-documenting code. And I just want put a caveat out here because I'm not suggesting that all code should be entirely self-documenting and there's no reason for documentation or using comments.
[00:08:06] But we can go a long way to helping ourselves, helping our future selves and our other team members by coming up with good useful names for stuff. If you don't come up with crappy names like foobar baz. If you come up with a good name like handleClickPresses, you're telling somebody I know exactly what that's doing.
[00:08:23] I know that's handling the click of it, right? So when you look at a function, for example a function being passed to a callback. If it's an anonymous function expression, you cannot tell by that function signature what the function's gonna do. So to understand that you have to first look at where it's being passed and at its code body to figure that out.
[00:08:44] But if you give it a good name, you immediately given the reader of your code more of a signal about what to do. Taken together, I think all three of these reasons are an ironclad argument. That's why I make the absolute statement. There is literally no argument in favor of the anonymous function expression except you are too lazy or uncreative to come up with a name.
[00:09:05] It's too onerous and burdensome for you to put a name on your function expression. And I'm going to completely include myself in that. Because every single time I write a function, I put it as anonymous and then I have to go back and I need that. Like I have to check myself every time.
[00:09:22] Because even years later I still have this as my default habit. And you're gonna see a bunch of anonymous function expressions in my slides. Cuz it's super easy to save space on slides and not come up with names, right. But this is definitely one of those do as I say, not as I do.
[00:09:38] In production code, you should always have names on your function expressions. It's more future-proof. It's more debuggable, okay. [COUGH] So when people are talking about putting names on their function expressions and, I don't wanna do this, and this is hard for me. Here's my process. It's just a suggestion for you about how to go about this.
[00:10:02] I've tried to get myself into the habit than when I write a function expression, the very first thing I do. If I don't already know what it ought to be called, like if I don't know handleClickEvent is the right name. I put the word to do there in capital letters.
[00:10:14] You know why I do that? Cuz I have that same habit with my comments. I'll put a to-do comment and I search through my code looking for to-do comments. And bam, it's gonna pop up if I've accidentally left that to do placeholder as the name for my function expression.
[00:10:27] So the first thing I do is I start out with a good placeholder instead of anonymous. There's a name there that's gonna catch my eye and let me know that I need to refactor that as some point. As I'm developing the function, I'm trying to figure out what I should call it.
[00:10:38] And I often don't know at the beginning of writing that function or what a good name for it is. As a matter of fact, it often takes me multiple attempts. I call it something and then I work a little more on it, and I refactor it. I'm like, that's a bad name now, let me rename this thing.
[00:10:51] And after about the third to four time I come up with a good useful names for that function, okay? So that's my process. I would encourage you to find your own process but I strongly recommend you consider working against your natural instinct and behavior and putting names on all your functions expressions.
[00:11:10] Refactor all your code to the add. You had a question.
>> Speaker 2: Yeah, this would seem to be huge to me. I think you said yesterday, 70% of the time coding is actually spent reading code. And it would seem that it would greatly improve when you're reading somebody else's code.
[00:11:30] And it's obvious this is your belief. Is this the industry belief, or is this, all of that installed code out there, is this considered a best practice by others in the general world, or is that a religious question?
>> Kyle: I was just about to say, adherence of my gospel of the JS books.
[00:11:50] They probably believe it. But in general I find the push in the other direction. Which is one of the reasons why I make such a big emphasis on this. In general I find the push towards, no let's not optimize for readability. Let's optimize for how quickly I can write stuff.
[00:12:05] Many of the syntactic additions to JavaScript where it went in the direction of let's just remove as many characters as we possibly can so that it's quicker to write code. And that optimizes for the development process and actually harms, I believe, the readability process. So I'm suggesting that we go in the other direction because I've been there in the trenches and I've seen both ways done.
[00:12:26] And it is harder to maintain code that is more cryptic because you saved a couple of extra microseconds when you were typing out the code. So I strongly believe it. I think people are starting to catch on to that if they follow my work. But I do not think you will find in general a large swathe of the industry that's followed that.
[00:12:44] In fact, you see lint or tools and things like that that suggest the opposite, which I think is not a good idea. Yes.
>> Speaker 3: In chat, Craig asked if there's a naming convention for named function expressions. And I said there's two hard problems in computer science, naming and caching.
[00:13:05]
>> Kyle: [LAUGH] Well there's three hard problems, right, because there's also counting [LAUGH]
>> Speaker 3: Counting, right, yeah.
>> Kyle: No, so definitely there is no one standard for the naming convention. I would advocate, don't use a naming convention. Use a specific name for that specific use case. Perhaps if you wanna think about conventions, you can say, do I wanna name my functions like nouns?
[00:13:31] Or do I wanna name them with the verbs in terms of what action they do? Do I want to name them in terms of what their end result will be, like what they will return? You'll come up with different names for them, based upon maybe that broad level macro kind of convention decision.
[00:13:46] But there's no way for me to say that you should always name it this way or something. It should be consistent in terms of style, so the casing should be the same and those kinds of things. Yeah, there's no, there's no overriding principle there.