A picture of myself

Atanas Stanilov

Part-time web developer. Full-time superhero.

Let there be const

IN: JAVASCRIPT
Dec 15th 201810 min read

With this I mark my first ever post in the vast world of internet. Hurray!

And a simple introduction is never needless: My name is Atanas Stanilov. I have been dealing with web development since 2015. Hence, I'll be writing about interesting things I learn on the curvy road to become a better developer. You can always Reach me to get to know me better.

I am open to every kind of feedback. Enjoy this article emoji-heart.


The year is 2015 and ECMAScript 2015(also known as ECMAScript 6 or ES6) was officially introduced to the web community by the good guys at ECMA International. It featured many major changes, some of which targeted a few "ancient" functionalities. Thanks to these changes, we can now use class instead of the well-known for many years prototype-based inheritance. Arrow functions, also, changed the way we write functions and are a real bugger for newcomers. However, they made it easier and prettier to write callbacks in a functional language as javascript itself. Also, the strict mode in ES6 added some strong rules on coding with javascript - like throwing an error when trying to assign a value to an undeclared variable and more.

A you've already noticed, this post is about two new keywords: let and const. These two offer a new way to define variables. For all these years we got clinged to use our favorite var keyword when defining a variable. And now we have to accept two more. I am not saying that var is dead, it's just that let and const offer something more.

A side story: I don't know about you, but for me, switching from strongly typed languages(C++/C#) to a loose typed one was a big tumble. Letting go of int, float, double, string and etc in favor of a single variable type name was so hard at the beginning. However, now I love the fact, that I have one less concern to worry about - figuring out what type of variable I'll need at the moment of it's creation. For all lovers of strong typing there is TypeScript of course.

Is var not enough?

To answer this question, we must first understand why is var a bit bizarre.

Lets start with citing the bible. Oh! I mean the official documentation, sorry.

The var statement declares a variable, optionally initializing it to a value.

Well this didn't gave us much at first glance. But wait until later, when we take a peek at the official description of let. So, basically, what they are stating is that we have a simple way to declare a variable. A good notice is that initializing it with a value is not mandatory. This is suitable, because most of the variables we declare have no initial values.

Declared variable in javascript is a variable that has been "described" to the compiler, but not initialized with a value. Simply said var myVar is a variable declaration. I really won't bother spending much energy on fancy variable names here.

A defined variable is actually a declared variable, but specifically assigned with a value - var myVar = 5.

Variable declaration and definition can happen at different times in our code:

var myVar   //we declare the variable
....        //some code executed here
myVar = 1   //here we define the variable with a value

Let's look at some other examples:

var myVar           //myVar is only declared, but not defined
console.log(myVar)  //this will output *undefined*, because, you see - it's value is not defined

As soon as we give myVar a value(define it), things get clearer:

var myVar = 5       //here we DECLARE the variable and at the same time DEFINE it with a value of 5
console.log(myVar)  //expected output will be 5

Assuming your javascript is using strict mode(all modern browser use this mode by default) - let's try something a bit different. More about strict mode in the official documentation here.

myVar2 = 10          //assigning the value 5, without officially declaring the value
console.log(myVar2)  //this will produce an error: "myVar2 is not defined"

This happens, because we tried to use a variable, which was not declared in this current scope. Read more about scopes and closures in the official documentation. This will not be covered in detail here. Keep in mind that not defined and undefined are two different things: the first is an error, the second is a valid primitive value.

Functions, or more precisely blocks, in javascript create their own scope called local scope, which is nested in the global scope. Let's say we had some local scope, in addition to the global one:

//global scope
var funcVar = 2

function theFunc(){  //just a casual creative function name, indeed
    //theFunc creates a local scope
    console.log(funcVar)  //expected output will be 2
    funcVar = 5
    console.log(funcVar)  //expected output will be 5
}

theFunc()  //execute the function in global scope

No "not defined" error is thrown here. This is because, yeah, you guessed right - variables defined in the outer scope are accessible in the inner scope. Variables defined in the global scope or outer scope are "visible" in every nested local scope. A variable defined inside a local scope is only accessible in the current local scope and not "visible" from outside.

Buuut, this is not exactly true with var declared variables. Consider the following:

//global scope

function theFunc(){
    //theFunc's local scope
    var funcVar = 1
    if(true) {
        //if creates it's own local scope
        var funcVar = 3
    }
    console.log(funcVar)
}

theFunc()  //executing the function in global scope

//from what we learned, here we'll expect the logged variable to be '1'
//because 'funcVar = 3' is defined in the scope, created by the if statement
//however, we get a value of '3', which means that funcVar's value gets overridden from the inner scope
//also, if instead of var we declared with 

What seems to turn out is that funcVar is actually accessible from the outer(currently created by function theFunc) scope. Even if you comment the var funcVar = 1 line, the returned value will still be 3. We expect throwing an error, because we want funcVar to only be available in the block, created by the if statement. But it doesn't. This makes our code prone to error if we want to define only local scope variables and don't want to erroneously try to use them from "outside".

Using the same example, but defining the variable in the global scope too, has the effect:

//global scope
var funcVar = 3

function theFunc(){
    //theFunc's local scope
    var funcVar = 1  //funcVar is defined in the local scope, global scope must not have access to it
    console.log(funcVar)
}

theFunc()  //executing the function in global scope, for the example it only defines a variable
console.log(funcVar)
//the output will be:
//> 1 //coming from execution of "theFunc()"
//> 3 //from global execution of "console.log()"

Wonderful! This means that funcVar's global value doesn't get overriden from the same variable definition in the local scope(function theFunc()). The overridden value is only in the scope of function theFunc().

What we learned in this first part of the post is that if we want to define a variable in a local scope and we want it to be only available in this scope, var will not do the job. We need something better, something specific.

LET IT GOOOO...

Let's get going and finish this post. It is getting too long and I am getting short of words emoji-sleepy.

We covered a lot about the var statement. Of course, there is more that can be noted, but this post is already coming near the "tl;dr" type. Surprisingly, almost everything is the same with let. Remember the effect of defining a variable in local scope and trying to access it within the outer scope we talked about? Well, hellooo theeere, we expected an error, but got undefined. Gosh... are you even following along? Maybe this post is really getting too long for a first one... What I am trying to say, obviously, is that one of the differences between var and let lies exactly here. Another one is javascript's hoisting, which I can assure you you already have used, maybe without even knowing. Shortly: variables defined with var get hoisted to the top of the memory during compilation of the code. However, those defined with let won't get hoisted. More about javascript hoisting here.

We should look at the official documentation again:

The let statement declares a block scope local variable, optionally initializing it to a value.

So we have a declares variable for var against declares block scope local variable for let and that's it. There's our main difference. Ain't no better way then proving it with an example:

function theFunc(){
    //theFunc's local scope
    var funcVar = 1
    if(true) {
        //if creates it's own local scope
        let funcVar = 3
    }
    console.log(funcVar)
}

theFunc()  //executing the function in global scope

//from what we learned about "var", here we'll expect the logged variable to be "1"
//because "funcVar = 3" is defined in the scope, created by the if statement
//however, this time, thanks to the "let" statement we get "1"

Thanks to let we managed to declare a fully encapsulated in the if's scope variable. Something, we couldn't achieve with var. Now if we accidentally try to use the same variable, without defining it in the outer scope, we will get punished with an error for our inattentiveness.

function theFunc(){
    //theFunc's local scope
    var funcVar = 1
    if(true) {
        //if creates it's own local scope
        let funcVarNew = 3
    }
    console.log(funcVarNew)
}

theFunc()  //executing the function in global scope

//now get that deserved "not defined" error, you little distracted-not-focused-piece-of... rascal

You can stick with var and completely ignore let statements for declaring variables, if you don't mind. However, my advice is to use the second statement when it comes to creating variables, which is going to be used in the local scope only.

So, which one wins? Well, both. If someone tells you that var is dead wish him the same. No, I don't want to play the bad guy who advises you to be rude. Be gentle, be kind...

Introducing javascript constants.

I really think about cutting this short. The reason is if I haven't lost you as a reader already, I'll definitely will.

The reserved const is a short name for, guess what? Yeah, constant. The const statement defines a variable with the exact same rules like using let instead of var statement. I mean, trully, the differences between const and var are exactly the same as those between let and var.

Stating the description:

Constants are block-scoped, much like variables defined using the let statement. The value of a constant cannot change through reassignment, and it can't be redeclared.

"A-haa", so there is something else on top of what we learned so far, Johnny! Of course, if you are the one creating new functionalities, you won't forget to add some spicy differences, will you?

Jumping to a concrete example:

const myConst = 1
myConst = 2
console.log(myConst)
//here we expect "2" but get a TypeError: "Assignment to constant variable."

The error speaks for itself. And so is the statement constant, but yet we still tried to change the value... The use case for this statement is to create variables, which are not prone to change and we know they'll keep their value throughout our code.

Buuut, this is not exactly true(yes, I copied this from above). I guess one of the reasons I liked javascript is that it can always surprise you emoji-sweat_smile. Because, this rule looks different for the Object data type.

Let's assume we have a nice sports car. Of course if give a shot to the next example, we will get the mentioned error:

const car = { brand: 'Nissan', model: 'GTR' }  //define a const "car" which is of type Object
//let's say that we no longer like this car and want to change it with something better(is there?)
car = { brand: 'Lada', model: '1500' }  // yeah, yeah, I know you are surprised
console.log(car)

Here, we won't even have the opportunity to reach console.log(car), because we made a mistake and an error is all we get: we tried to change the unchangeable, constant variable const car. But, we are really into upgrading to a better vehicle and we are too lazy to refactor our code to var or let. So we can legally do this:

const car = { brand: 'Nissan', model: 'GTR' }
car.brand = 'Lada'  //ah, the stubborness
car.model = '1500'
console.log(car)
//finally, some output!: Object { brand: "Lada", model: "1500" }

Shock and awe! We changed the value, which was a constant. This is actually not surprising, I was overreacting. Only the object itself, defined as a constant, is protected. Object keys are not. This is effect intentional and really helpful, you will see.

Since in javascript everything is an object, the same effect can be seen with arrays.

const arr = []
arr[arr.length] = 1
console.log(arr)
//Array: [1] //this is possible and no error is thrown again
arr = [2]
//this is not allowed, we get an error because we change the whole array

And again, using const is only optional. Yet, it introduces some useful restrictions to the actions we take on variables. Using ReactJS, which is 90% javascript, I tend to use const for variables I know will not change their values during execution of the code. This makes my code more concise and readable. My advice is to stick with const whenever reasonable.

I hope you enjoyed this article emoji-blush.


Don't hesitate to contact me to report any mistakes or just to say hi.

#javascript #es6

Next

...

Copyright © 2021, Atanas Stanilov

Made with lots of and ❤️

Contact me