Deep JavaScript Foundations, v3

Choosing let or var

Kyle Simpson

Kyle Simpson

You Don't Know JS
Deep JavaScript Foundations, v3

Check out a free preview of the full Deep JavaScript Foundations, v3 course

The "Choosing let or var" Lesson is part of the full, Deep JavaScript Foundations, v3 course featured in this preview video. Here's what you'd learn in this lesson:

Kyle analyzes the choice of whether to choose let or var in the contexts of performance and code communication.


Transcript from the "Choosing let or var" Lesson

>> Kyle Simpson: Now my argument is that even though you could do both of these with let, you should only do the variable on the for loop with let. If you have a variable that belongs to the entire scope of the function, the correct syntactic way to signal that to your reader is not to use a let at the top level of your function scope, but to use a var cuz that the thing it's always done for 24 years.

>> Kyle Simpson: If you were to replace the var online with a let, even though in this particular example it would still functionally work. My argument is that it would remove a small amount of important semantic information from the reader, because the reader would then not know, well what is your intent?

Is your intent for me to use it everywhere or is your intent for me to only use here at the very top of the function? I don't really know, because lets are supposed to signal a very localized usage of a variable, ideally within only a couple of lines of code.

And if you're intent is to use the variable across the whole function, the let keyword might work, but it's not the right tool. It's not the right usage of the tool. You've heard that adage before, if you are gonna put a screw in or you're gonna put a nail in, you should choose the right tool, hammer versus, all right.

But I'm gonna extend that analogy, cuz not only should you choose the right tool, if I had a nail and I had a hammer, I've done some home repair and I could probably reasonably put a hammer into a wall, put a nail into a wall, okay. But what would happen if I had the same tool and the same nail and to put the nail in the wall, I put the hammer in my mouth and I just did, [SOUND].

I have the right tool for the right job but I'm using the tool the wrong way. It's not enough to have the right tool, you need to use the right tool the right way. So even though let might be a tool that would work, it's not being used in the correct way.

>> Kyle Simpson: The var keyword here is a more appropriate tool to say I have a variable that should be used across. Here's a thought experiment, imagine somebody were to design a programming language that only allowed you to access any parameters to a function on the very first line of the function.

And beyond the first line you couldn't access the parameters. How many of you would find that to be a fun language versus how many of you would find that to be an annoying restriction in a language? I think the reason, and this is what I'm getting at, is it is natural within the design of code that some things are not block scoped.

Some things are, and if you have something that is naturally block scoped, please use let. I'm not saying anything about let, use let to block scope, that's exactly what it's for. But please don't go looking to make things into lets that aren't naturally lets. Yes?
>> Speaker 1: So if you use ESLint, I think the default setting is that if you use var, then you get the unexpected let, or the other way around, right.

>> Kyle Simpson: That's true. And I just disagree with them, and I have that rule turned off in my own ESLint, okay. Any tool that doesn't allow you to customize it and instead enforces its own opinion on you, is a tool that's not helping you, it's getting in your way.

And I would argue it's not really getting in your way in a helpful way. It's getting on your way and preventing you from communicating. Yes?
>> Speaker 2: To review for line two, if we have var or let, will the variable function in the same way in the-
>> Kyle Simpson: In this particular code snippet they will behave the same.

So all I'm making the case right now on this exact slide is a stylistic argument. I'm about to make a bigger case for why you sometimes want var, but right now I'm only making a stylistic argument for var. A semantic argument for var, okay. [COUGH] So if you have a variable that is going to show up in a place that would otherwise be considered a block and you use a let, guess what happens to that variable?

Whether you want it to or not, it attaches to that block. One of the examples that I often run across is if I'm trying to use a let and I use it inside of a try-catch block, I don't think of try-catch as a block, I don't think of it as a scope.

I think of it as a syntactic way to catch exceptions, not even a particularly well designed one, but it is how we catch exceptions. I certainly don't think of it as a place for me to hide scope. And yet, the let keyword and the const keyword block scope themselves inside of it.

So guess what would happen if we did our global find and replace from var to let? This code would break because there wouldn't be an id on line nine. Var hoists, we'll get it back to hoisting, but var attaches itself to the function scope. And I would argue in cases like this, which arguably are not all the time, but in some cases, the var keyword is preferable to the let keyword because it is able, in this case, to escape an unintended block.

>> Kyle Simpson: The alternative here would have been to declare a var outside of the try, just like we did a few slides ago, and then assign to it in two places. And I would argue that the more that you add lines of code to that, the further you separate the declaration from the assignment, the harder it is for people to understand.

So this is one of those places where I tend to prefer using something like a var. While we're on the topic of var, another thing that var can do which let can not is that you can use var more than once inside of a scope. Here var is being used twice within a function scope, and we're not gonna get any exceptions whatsoever.

And I used the var online six because I was trying to disambiguate where id comes from. This is a semantic signal that I'm sending to the reader, regardless of which path we go through, there's gonna be an id in the function scope and it's gonna have a value.

So I put var in both places, and I can do that because that's what var can do. I can't do that with a let. I don't do this that often, as again as I've said. This is not something that happens a lot in the code. But in the places that it happens, I think that it is better that var is a tool that has a different capability then does let.

And if I had adopted some ESLint rule that completely forbid all uses of var, I would be restricted in this scenario. Here's another place where I like to use the var for the disambiguation of scope. I tended to prefer my functions to be no longer than about 15 or 20 lines of code.

Cuz I'd like to have all of my functions be visible on my code screen at once, in my editor at once. But every once in a while, maybe more often than I'd like to admit, my functions are 100 lines or 200 lines long, it does happen. Some of you probably have some long functions, okay.

If I declare on line one of a function some variable and it's called teacher and I'm using it for some purpose, and I use it for a few lines and then we go down 200 lines and then I need to use the variable again. If I just start accessing it and assigning to it, and the reader is scrolled all the way down there and they see that teacher, it is not gonna be clear to them what scope it comes from.

How are they gonna solve that? They're gonna have to scroll 200 lines up and go look for a var teacher.
>> Kyle Simpson: What I like to do is any place where I'm going to reuse a variable in a place where it's not obviously already having been declared, is I redeclare it to make it clear and completely unambiguous what scope it belongs to.

So I put another var id down on line 200 to show you that I'm using a variable called id in this scope, regardless of whether it was declared only once or being redeclared. Vars can be reused within a scope, lets cannot. So there are both semantic reasons and behavioral reasons why I think var and let should coexist in your program rather than having one be the other.

As a matter of fact, I would say, essentially no time in all of computer science history has that ever really been true, that x is the new y. That's just not a thing. We create new stuff, but it almost never, in the whole scope of everything that we've invented, it is almost never the case that when you create a new thing it completely and totally obviates the previous thing immediately.

It's almost always that it augments. And so what we have here is an example where we love to write blog post that say let is the new var and we love to have t-shirts that say that and we love to do global find and replaces, but in reality let is not the new var, it is let plus var.

They both are useful for our programs. You had a question?
>> Speaker 1: Yeah, if you, like in this case, if you have id twice. Is then the var stored in the same memory location or are there two memory locations that reference each other or?
>> Kyle Simpson: Just one marble. Remember from our earlier example, when we run across the second var on line six during the compilation phase, we would have said, hey blue scope, hey scope of lookup record, ever heard of this thing called id?

And he would have said, yep, and he would have said, okay cool, nothing to do, no op. There's already a marble called id.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now