loading...
Cover image for JS fundamentals: const vs var vs let?

JS fundamentals: const vs var vs let?

christianmontero profile image Christian Montero ・6 min read

A lot of features came out with ES6 (ECMAScript 6. ES2015, Harmony, ESNext), many of these features are already supported by the newest features.

One of these features is the incorporation of new ways to declare variables, but you might be wondering what's the difference? what makes them better than our friendly var?

In the next posts we are going to be discussing the Javascript fundamental concepts so we can switch to the latest syntax if we haven't yet. In this post we will discuss about the differences between var, let and const in relation to their use, hoisting and scope.

Terminology 📕

  1. Scope: In Javascript the scope refers to the current context of code that determines the accessibility (visibility) of a variable. There are 2 types of scope:

    -Global Scope: Variables declared outside of a block.
    -Local Scope: Variables declared inside of a block.

  2. Hoisting: Is a Javascript mechanism that moves the declaration of variables and functions to the top of their scope before code execution.

We will talk more about this concepts later on this post.

Const ❗️

Const doesn't mean "constant" it means one time assignment

Const cannot be updated or re-declared

Const keyword is a litttle tricky especially if you have used them in other languages. A constant is a variable with an inmutable reference. When we declare a primitive type as const we cannot change its value, if we try, we will see an error in the console, as you can see here:

const PI = 3.1415926535;
console.log(PI);
PI = 3.1416;
console.log(PI);

Console Error


The same way if we try to re-declare a const variable we will see this error:

const PI = 3.1415926535;
const PI = 3.1416;

Console Error


This means that when we want to declare a variable using the const keyword, we must initialize them at the time of the declaration or we will see another error message:

const PI;
PI = 3.1415926535

Console Error


However this behavior changes when it comes to non-primitive types (objects, arrays, etc) as const. The way the const keyword works with objects is this:

We cannot re-declare the object but we can update the value of its properties and we can add more properties without returning errors.

const user =  {
  name: 'Obi-Wan',
  age: 30
};

console.log(user);

user.name = 'Luke';
user.lastname = 'Skywalker';
user.age = 25;

console.log(user);
};

Console Output

Const is block scoped

Before ES6 we had local/function scope and global scope.
function-scoped variables were only available inside the function where they were declared. Now with ES6 and with the addition of the let and const keywords, we have the block scope where block code means the code bounded by {}, anything within curly braces is a block. We will this explain in the next example:

const PI = 3.1415926535;

function cirleArea( radius ){
  const PI = 3.1416;
  console.log('PI inside circleArea function: ', PI);
  return radius*radius*PI;
};

console.log('PI outside circleArea function: ', PI);

var area = cirleArea(1);
console.log("The area is: ", area);

Console output

As you can see, we define a PI constant outside our circleArea function, and we define another constant with the same name inside our function, since they have different scope, we won't run into a re-declaration error, also if we console log both of this variables in their respective scope, we will see the different values.


Hoisting of const

const delcarations are hoisted to the top but is not initialized. so if we try to use a const variable before its declarations, we'll get a Reference error.

console.log("The value of PI is: ", PI);
const PI = 3.1415926535;

Console Error

Let ✅

Javascript now has lexical variable scoping, we create code blocks with curly backets. With functions, these curly brackets block off the scope of variables, but if we think about if-else statements, we might assume that these blocks would also block variable scope, before the addition of the let keywork this wasn't the case as we can see in the next example:

var name = 'Peter Griffin';

if(true){
  var name = 'Homer Simpson';
  console.log(name);
}

console.log(name);

Console Output

The name variable inside the if block resets the value of the global name variable.

Fortunately with the let keyword, we can scope a variable to any code block. Using let protects the value of the global variable and that's why let is now the preferred for variable declaration.
We can see the same example here:

var name = 'Peter Griffin';

if(true){
  let name = 'Homer Simpson';
  console.log(name);
}

console.log(name);

Console Output

Unlike const, let can be updated but not re-declared

Any variable declared with the let keyword can be updated, but if we try to re-declare it, we will get an error as we can see in the next example:

let name = 'Peter Griffin';
console.log(name);
name = 'Homer Simpson'
console.log(name);

Console Output


let name = 'Peter Griffin';
console.log(name);
let name = 'Bart Simpson';
console.log(name);

Console Error

Let is block scoped

A variabled declared in a code block using the let keyword will be only available within that block.

Hoisting of let

The same way that const, let delcarations are hoisted to the top but they are not initialized, so if we try to use a const variable before its declarations, we'll get a Reference error.

What about our old friend var? 👨‍🦳

Most of the time we can replace let with var and vice-versa and expect things to work, but there are some important points that we have to know.

var has no block scope

When we declare a variable using the var keyword they are either function-wide or global. They are visible through blocks:

if(true){
   var name = 'Peter Griffin';
}
console.log(name);

Console Output


As we can see, even when we declare the variable inside the if block, the variable lives outside. We will see the same behavior with for loops blocks. The only different scenario is if the code block is inside a function, in that case the variable becomes a function-level variable.

if(true){
   var name = 'Peter Griffin';
}
console.log(name);

Console Error


var can be re-declared

var can be declare below their use (This is possible because declarations are hoisted, but assignments are not)

function add(a, b){
  result = a + b;
  console.log(result);
  var result;
};
add(5, 2);

Console Output


💡 Summary 💡

  1. Scope means the code context where variables are available for use. 👀
  2. Hoisting is a Javascript mechanism that moves the declaration of variables and functions to the top of their scope before code execution. 🔺
  3. Const doesn't necessarily means that holds an immutable value, it means that holds an immutable reference and it behaves different depending the type of variable that we assign to. But even though our code can be more meaningful if we use the const keyword. 👍
  4. Let is similar to var, but let is block scoped. 💪 5.- Reading across many articles I found that many authors recommend to avoid the use of var, there's no need to use it anymore. 👎

I believe that there's always something to learn from everyone, hopefully this post will be useful for somebody, I'm still learning, so any feedback would be appreciated. Have a nice day! ✌️

Posted on by:

christianmontero profile

Christian Montero

@christianmontero

I'm a sw developer focussed on web development 🧑🏽‍💻 amateur coder but always looking to improve and learn new things

Discussion

markdown guide
 

However this behavior changes when it comes to non-primitive types (objects, arrays, etc) as const.

Actually, it doesn't change at all.

const x = y;

This means that you may not reassign x, and this is true regardless of y having a primitive of object value.

The confusion is due to conflating the properties of an object with the value of the object.

The value of the object is the object's identity, and this allows you to access the properties associated with that object.

These properties can be modified, but modifying the properties does not change the value (or identity) of the object.

non-primitive types (objects, arrays, etc) as const.

When you use const, it has nothing to do with the value -- const only affects the variable.

 

Thanks for correcting my mistake, I really appreciate it! 👍

 
 

Thanks for this publication.

I think you have doubled following code in var has no block scope section

if(true){
   var name = 'Peter Griffin';
}
console.log(name);

and probably not related screenshots.

 

var still has uses, its particularly useful when you want to declare global variables inside a script, also it could be used to signal that an identifier is function scope and is available throughout the whole function

Also hoisted declarations dont actually get moved, hoisting means that when the function is compiled the instructions to register a variable is placed & executed first, yes javascript is a compiled language not in the same way as something like c or c++ where the code is compiled in advance but instead javascript code is JIT (just in time) compiled the javascript standard doesnt require compilation specifically but it it requires a parse phase.

 

Hoisting does actually move the declaration -- but it does not move the initialization, which becomes an assignment.

So the difference between 'var' and 'let' are two:

  1. var is scoped to the whole function; let is scoped to the whole block.
  2. var is always initialized; let is initialized at the point of declaration, and may not be accessed until initialized.

Javascript is a compiled language

This is a category error.

Javascript implementations may be compilers or interpreters or some mixture of the two.
It is not a property of the language.

 

JS behaves much more like a compiled language than an interpreted one, the code has to be parsed first it then compiled regardless of whether or not the compiled code is machine code or some other byte code format that gets interpreted, the point is JS code gets compiled it's hard to imagine that a production quality is engine parsing the code into an AST and not compile it and optimize it.

Hoisting doesnt move anything, again by move I mean re arranging the code so the declaration is on top of the scope that doesnt actually happen .... when the code gets compiled instructions to register variables are compiled and executed first that it's the engine doesnt rearrange or pre process anything it just turns your code into an efficient executable binary, that's how most JS engine execute code these days and yes JIT compilation IS a property of the language.

"compiled language" and "interpreted language" are nonsensical terms.

There are python compilers, and there are C interpreters.

These are implementation strategies which can be applied to any language.

Hoisting does effectively rearrange the code so that the declarations are at the top of the scope.

See the algorithm in 18.2.1.3 of ecma-international.org/publication... for example.

JIT compilation is not part of the language specification.

I suggest reviewing the language specification, as it may clarify many of these issues for you.

 

When going to var you must let yourself expect a const ant resistance.