Importance of Natural Resources

var vs let vs const: Variable declarations in ES6 | ES2015


ES2015 introduces two new ways to create variables,
let and const. As you probably know by now if you’ve watched
any of my videos I don’t really like to make assumptions as to what you know. With that said, before we start talking about
the difference between var, let, and const, there are three things we need to talk about
first. They are variable declarations vs initialization. Scope, specifically function scope, and hoisting. Now I realize you might already know those
three things so if you do, feel free to fast forward. But for now, let’s talk about variable declarations
vs initializations. A variable declaration introduces a new identifier. Here, we create a new identifier called declaration. In JavaScript, variables are initialized with
the value of undefined when they are created. So if we log the declaration variable, we
get undefined. Initialization is when you first assign a
value, to a variable. So here, we’re initializing the declaration
variable, by assigning it to a string. This leads us to our second concept, scope. Scope defines where variables and functions
are accessible inside of your program. In JavaScript, there are two kinds of scope
– global scope, and function scope. According to the official spec, “If the variable
statement occurs inside a FunctionDeclaration, the variables are defined with function-local
scope in that function. Otherwise, they are defined with global scope,
that is, they are created as members of the global object”. What that means is if you create a variable
with var, that variable is scoped to the function it was created in and is only accessible inside
of that function or, any nested functions. If you create a variable without using var,
that variable is created as a property on the global object. So let’s take at what this looks like. Say we had a function called getDate and it’s
honestly going to be a pretty basic function. Say we had a date here and then now let’s
go ahead and return date. So what we’ve done is we’ve created a variable
called date inside of our getDate function. As you probably know, we can invoke getDate
to give us the date, but, if we try to access date from outside of this function, we’ll
get a reference error because we created the date variable inside of this function so only
this function as well as any functions inside of it can access date. For example, if we created another function
in here for some reason, we’ll call it formatDate, and then what we’ll do, is we will return
date.toString and then we’ll format it a little bit. So now instead of returning date, we can return
the invocation of calling formatDate. And notice here that our formatDate function,
because it’s nested inside of our getDate function, still has access to the date variable,
but outside of the function we do not have access to it because date is scoped to this
getDate function. Now I realize this is a pretty basic example
so let’s go ahead and take a look at a more complex example. So let’s create a function here, we’ll call
it discountPrices. This function is going to take in a prices
array as well as a discount. And then what it’s going to do is it’s going
to loop over the prices array, and for each item in that prices array, we’re going to
discount it and then we’ll return this brand new array full of our discounted prices. So we’ll create a for loop here, and for each
price in our prices array, we will create a discountedPrice variable which is going
to be the specific price times one minus the discount that was passed in. Then we will create a final price which is
just going to use Math.round so that way we don’t have any floating point errors. And then once we have that final price, we’ll
go ahead and push that into our discounted array. So now the last thing to do is just return
discount. So if we were the invoke this function, let’s
just say we passed in an array of 100, 200, and 300, and a discount of .5, what we would
get back is a brand new array with all of those values halved. So now to better demonstrate that variables
declared with var are function scoped let’s go ahead and console.log a few items right
here. So first, let’s go ahead and console.log i,
and then we will console.log the discountedPrice variable and lastly, we’ll console.log finalPrice. So if we grab this, then we will head over
to our console let’s go ahead and run this. You’ll notice here that what we got was 3
for i, 150 for discountedPrice, and 150 for finalPrice. Now if JavaScript is the only language that
you know, you’re probably not too confused or too surprised about what’s going on here. But, if you’re coming to JavaScript from a
different programming language, specifically, another language which is block scoped, you’re
probably a little bit concerned about what’s going on here. This isn’t really broken, it’s kind of just
weird. You’ll notice that we still have access to
our i variable even though we are outside of this for loop. In fact we still have access to all of our
variables, even though there’s really no reason to have access to any of these variables outside
of this for loop. It doesn’t really do us any good, and eventually
it might even cause us some harm. But, because variables declared with the var
keyword are function scoped, again, these variables right here, can be accessed anywhere
inside of this function. Now that we’ve discussed declarations, initializations,
and scope, the last thing before we can dive into let and const is hoisting. When the JavaScript interpreter evaluates
your code, it will move all function and variable declarations to the top of the current scope. This is referred to as hoisting. So when you write something that looks like
this, the interpreter will change it into this. Why does this happen?I don’t really know,
and honestly I don’t really care. But I do care that it does happen, and I do
care that I know what’s going on when it does. Let’s take a look at the previous example,
and see how hoisting affects it. Here we have our discountPrices function that
we created earlier. So what’s going to happen when the JavaScript
interpreter evaluates this code, is it’s going to take all of our variable declarations and
hoist them to the top of this function. So, once interpreted, all of this code is
going to change from this, to this. With all of our variable declarations being
hoisted, and now, because all of our variables have already been declared, if we want to
reference any variables, we simply reference them by their identifier. Now as a quick side note, you may have remember
earlier when I read the specification about declaring variables, I said that if you don’t
declare a variable with the var keyword, then that will become a property on the global
scope. And the reason for that is because of hoisting. So again what happens, our variable declarations
are hoisted, so now, when we have a variable discounted it looks inside of the scope for
a declaration of the discounted variable. If it doesn’t find it, it will go to its parent
scope, and look for a declaration of discounted, and it will do that all the way until it gets
to the global scope. So if we go back to our original code, if
now, we leave off this var keyword, what’s going to happen is when the JavaScript interpreter
evaluates this code now, it’s going to change it to this, then, it will look for a discounted
declaration inside of this function. It won’t find one, because we left off the
var keyword, so then it will go to the parent, and it’ll repeat that process all the way
until it gets to the global scope and then once it doesn’t find a discounted declaration,
it will add discounted as a property to the global scope. So that’s why you should never declare a variable
without a var keyword, because if you do that, whatever that variables name is will become
a property on the global scope, which is a terrible idea. Now that we know everything there is to know
about var, let’s finally talk about the whole point of why you’re here. How does var, compare to let or const? First, let’s compare var and let. The main difference between var and let is
that instead of being function scoped, let is block scoped. What that means is that a variable created
with the let keyword is available inside the block that it was created in as well as any
nested blocks. When I say “blocks, I mean anything surrounded
by a curly brace like in a for loop or an if statement. So now looking back to our discountPrices
function one last time. You’ll remember that when we console.log these
variables, what we got were 3, 150, and 150. That’s because we declared the variables with
the var keyword which meant that they were function scoped. Meaning, they were able to be accessed inside
of this function. But now what happens, is let’s come in here
and let’s change all of them to let. And I will copy. Now when we go to run this, what’s going to
happen, is you’ll notice that we get a reference error. i is not defined. So right here we are trying to access i but,
because we declared i with the let keyword, instead of var, that means i is only scoped
to this specific block right here. To show you this, let’s go ahead and change
this to var. Now if I run this, you’ll notice I get discountedPrice
is not defined because again discountedPrice was declared with the let keyword, which means
it’s only accessible in this block right here. The next difference has to do with hoisting. As we saw with var, referencing a variable
before the variable is declared will give you a value of undefined. This isn’t very intuitive, as we probably
shouldn’t be referencing variable before they’re declared anyway. Luckily for us, let fixes this. Variable declared with the let keyword, will
hoist the variable declaration to the top of the block just like with var, but, referencing
the variable before the declaration will result in a reference error. To see this in action, let;’s revisit our
hoisting example we saw earlier with var. Even though we’re logging the hoisted variable
before the variable is declared, because of hoisting, the interpreter will modify our
code to look like this. So when the hoisted variable is logged, we
get undefined. However, with let, the interpreter will still
hoist the variable declaration but unlike var, if you try to reference a variable before
the declaration, you’ll get a reference error. So to recap to far, unlike var, variables
declared with var will be block scoped and, trying to reference them before they’re declared
will throw a reference error. Now that we understand the difference between
var and let, what about const? Turns out, const is almost exactly the same
as let. The only difference is that once you’ve assigned
a value to a variable using const, you can’t reassign it to a new value. Let’s dive a little bit deeper into const
because there are some common misconceptions. We’re going to make two variables. The first one we’ll call name, and we will
use the let keyword. The second we will use const and we will call
it handle. Both of them will be strings. Now, if I wanted to reassign a new value to
name, I can do that just by like you’re used to, saying name=’Tyler McGinnis’. But, if I try to reassign a new value to handle,
what’s going to happen is we’ll get this error right here saying “uncaught type error: Assignment
to constant variable”. So with const, once you’ve assigned a variable
a value, you can’t reassign it a new value. Notice I’m being pretty clear with my words
when it comes to const. We can’t reassign a new value to const. This is where it gets a little bit tricky. Say we had a person object that we declared
with the const keyword. We’ll just give it a name property. Notice, what I can do, I can come in here
and say person.name=’Tyler’. Because what I’m not doing, is I’m not reassigning
person a new value. Instead, I’m just modifying an existing property
on the person object. So if we look at our person object now, instead
of being “Tyler McGinnis”, it’s just “Tyler”. But what I can’t do, is I can’t come in here
and say person now equals a new object, because, since we declared it with the const keyword,
we can’t reassign it a new value. So that’s why you need to be careful with
const because const variable aren’t immutable. You can still change them. They just can’t be reassigned a new value. Now the last question we need to answer, is
which one should we use. The popular opinion, and the opinion that
I subscribe to is that you shouldn’t always use const unless the variable is going to
change. The reason for this is by using const, you’re
telling your future self as well as any other future developers that use your code that
this variable shouldn’t change. If it does change, you should use let, like
in a for loop. So between variables that change change and
variables that don’t change, there’s really no other use cases so that means we really
never need to use var again. Now the unpopular opinion, though it still
has some validity to it, is that you should never use const, because, when you use const,
what you’re trying to do is you’re trying to say “this variable will never change”. Unfortunately, if that variable is an object
as we saw earlier, it can still change. So to recap, var is function scoped and if
you try to use a variable declared with var before the actual declaration, you’ll just
get undefined. const and let are blocked scoped and if you
try to use a const or let variable before the declaration you’ll get a reference error. And the difference between let and const is
that once you’ve assigned a value to const, you can’t reassign it, but with let, you can.


Reader Comments

  1. Great video! Is the benefit of "let" more for semantics of the code/readability? Or are there scenarios where you would want to throw unreferenced errors? Also does block scope allow you to reuse that same variable in multiple blocks? Im not 100% sure what the application of block scope is in javascript. Cheers in advance for any responses.

  2. You have a knack for these tutorials. Super clarifying. Definitely will remember to use const, then let where I know the variable will change.

  3. How can a variable be initialized twice? It's mentioned that a variable is initialized with a value of undefined when it is created. After all, initialization refers to the assignment of an initial value.

    Shortly after in your example, you say the the variable is initialized with a string. I like to think of that as more of a subsequent assignment of a string than an initialization.

    Or is initialization considered the explicit assignment of a value to some variable? Therefore, the implicit value of undefined at variable creation is not its initial value?

  4. Great video, Tyler! However I think that there is a mistake in the video about let hoisting:
    @"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let""
    "In ECMAScript 2015, let bindings are not subject to Variable Hoisting, which means that let declarations do not move to the top of the current execution context. Referencing the variable in the block before the initialization results in a ReferenceError (contrary to a variable declared with var, which will just have the undefined value). The variable is in a "temporal dead zone" from the start of the block until the initialization is processed."

    E.g.:
    console.log(c);
    let c;
    // Uncaught ReferenceError: c is not defined at <anonymous>:1:13
    // —> example that let are not hoisted

    let d;
    console.log(d);
    // undefined

    What do you think about that ? 🙂

  5. Great explanation! Remembering that using const you can not just change a property inside an object but create new properties as well. You can do something like:

    const person = { name: 'Tyler' }
    person.website = 'tylermcginnis.com'

    // {name: 'Tyler', website: 'tylermcginnis.com' }

  6. Great video. Thanks for making it. Is there ever any reason why you would use 'var' now that 'let' is available? Are there any use cases where 'var' is needed over 'let'?

  7. Thanks for explaining it well. I never really thought of var as confusing and don't think I've ever ran into major issues with redeclaring or that sort of thing, but I guess I could see in very large scale applications how you would maybe want to avoid any possibility of that happening.

  8. So at 9:50 or so you mention the let will still hoist, isn't one of the facts about let is it doesn't use variable hoisting?

  9. It was easy to understand. But one thing you didn't mention is that variable created using const needs to be declared and initialized at the same time.

  10. by the way great video but why does everyone have this big misconception about variables in JavaScript? there is no such thing as hoisting. Perl is the same way. being a managed code developer (C, C++ etc) I know that this hoisting your referring to is due to the way an interpreter has to work. to run your script, the interpreter has to load the entire script into memory, when this happens the variables are assigned memory space much like we have to do do with alloc() in C. that's why you get undefined, because it exists in memory space but has no value. so what is really happening is due to way an interpreter works, in order to not run like a slug, it allocates memory on the heap for all your variables, now it can't assign the values due to the fact the variable may or may not change multiple times so the variable is allocated memory space but assigned no value. its not re-arranged in the code its just pre-allocated on the heap by the interpreter code so that it runs faster. in turn this causes a lot of confusion as to what is happening.

  11. This was absolutely wonderful! Great explanation and awesome use cases in under 15 minutes of content. Wish I had found this channel sooner. Subscribed!

  12. Great video!! Could you pls talk about Return? I thought return can make the local variables be accessed globally. but why we cannot console.log the date outside of the function, even thought when we returned it?

  13. 🚀 Try our new 2019 React Course – https://tylermcginnis.com/courses/react/?s=youtube-var-let-const-variable-declarations-es6

Leave a Reply

Your email address will not be published. Required fields are marked *