DEV Community

Cover image for 1. let, const and ... var
Islam Sayed for Blue Turtle

Posted on • Updated on

1. let, const and ... var

ES6 has introduced some new syntax features. One of them was key words const, and let to declare variables. Let's talk about why they are preferred over var.

Scope🔭

var has a function scope. This means it is accessible anywhere in the function it is defined inside. See this example:

function buyHerChocolate(onDiet) {
    if (onDiet) {
        var decision = "Don't do it!";
    } else {
        var decision = "Go buy it!"
    }
    console.log(decision);
    }
buyHerChocolate(true);//"Don't do it!"
console.log(decision);//Uncaught ReferenceError: decision is not defined

As you see decision variable defined with var was availabe inside the function scope, but when we tried to log it outside the function the console throws an error decision is not defined as if it's never existed.

On the contrary, let and const have block {} scope.

function buyHerChocolate(onDiet) {
    if (onDiet) {
        let decision = "Don't do it!";
        console.log(decision);
    } else {
        let decision = "Go buy it!"
        console.log(decision);
    }
    console.log(decision);
    }
buyHerChocolate(true);
//"Don't do it!"
//Uncaught ReferenceError: decision is not defined
console.log(decision);//Uncaught ReferenceError: decision is not defined

Surprise! Logging the value of decision inside the expression block resulted in the predicted string while doing the same out of the block throw error and out of the function scope also throws an error.

The same happens with const.


Hoisting

Variables declared with var are hoisted to the top of their scope. It is important to notice that the variable declaration is what is being hosted not the assignment.

console.log(x);
var x = 5;//undefined

What happened?! The console.log() function will not get executed until hoisting any var variable. Therefore, var x; will go up to the top of the global scope. Then console.log(x) is executed and logs undefined, because x has no value at that time. The x is assigned the value 5. It will look like this:

var x;
console.log(x);
x = 5;

Because of that if we console.log(x) after that it would log 5 to the console.
This quirky behavior can introduce bugs in larger programs.

let and const are not hoisted.

console.log(x);
const x = 5;//Uncaught ReferenceError: x is not defined

Declaration & Assignment✒️

var variables can be re-declared and reassigned different value multiple times in the same scope.
let variables can not be re-declared but can be reassigned in the same scope.
const variables can not be re-declared or reassigned in the same scope. In addition to that they must be declared and assigned a value at the same time. So we can not do that:

const y;//Uncaught SyntaxError: Missing initializer in const declaration

But we must do that:

const y = 5;

So if your variable would have changed values, declare it using let, if not always use const.

These differences between them and var will prevent naming conflictions.


Conclusion:

For the mentioned reasons you should use const in all cases except when the variable would be reassigned new values. At such cases use let instead. Most of articles recommend developers to avoid using var. Why would anyone use var anymore?!

Do you agree with me about that? Please, leave a comment telling me your opinion.


For further readings:

📌The Difference Between Function and Block Scope in JavaScript

📌Demystifying JavaScript Variable Scope Hoisting

📌What is Hoisting in JavaScript?

Top comments (18)

Collapse
 
adrianhelvik profile image
Adrian

var is useful with Jest.

try {
  await foo()
} catch (e) {
  var error = e
}
expect(error.message).toMatch(/foo/)
Collapse
 
cms profile image
Christian C. Salvadó

Honestly, I would simply:

await expect(foo()).rejects.toThrow(/foo/)

Since foo is an async function, it implicitly returns a promise so you can use the .resolves / .rejects matchers and then use the toThrow method, and this accepts a regex or string to match the error message property. IMHO it reads more semantically correct.

Cheers,

Collapse
 
qm3ster profile image
Mihail Malo

The toThrow API is quite weird.
If you pass a string, it matches it anywhere, so 'foo' and /foo/ is the same.
And if you want to strictly match the whole message, you need to do

.toThrow(/^literal message$/) // RegEx with ends
.toThrow(new Error('literal message')) // The Error class does NOT matter in this case.

If you actually care about the constructor, you have to pass just it.

.toThrow(SpecialError)

I use

expect(badFunc).toThrowErrorMatchingInlineSnapshot()

a lot nowadays.

Collapse
 
youbicode profile image
A.

Any reason to not put the expect inside the catch bloc ?

Collapse
 
qm3ster profile image
Mihail Malo • Edited

Yes. If it doesn't throw assertion wouldn't run, and the test would pass.
You'd have to do

expect.assertions(1)
try {
  await foo()
} catch (e) {
  var error = e
  expect(error.message).toMatch(/foo/)
}

Personally, I'd just go with

await expect(foo()).rejects.toThrow('foo')
// Or, if final in the test:
return expect(foo()).rejects.toThrow('foo') // doesn't require `async` `it`

(No need for expect.assertions(1) since the expect runs synchronously inline)

Collapse
 
islam profile image
Islam Sayed

Could you please explain why you use only var with jest?

Collapse
 
adrianhelvik profile image
Adrian

Oh, no. I only ever use var in this scenario. Lets me skip out of the block scope without a separate variable declaration. And if no error happens, the variable is just undefined.

Thread Thread
 
islam profile image
Islam Sayed

Aha :)
So here is a place where var is still useful 😉

Thread Thread
 
qm3ster profile image
Mihail Malo • Edited

@adrianhelvik
Did you mean:

let error
try {
  await foo()
} catch (e) {
  error = e
}
expect(error.message).toMatch('foo') // you can use string literals if you don't have a complex RegEx
Collapse
 
avatsaev profile image
Aslan Vatsaev

If i see var in your codebase, you're doing it all wrong, even seeing let would rise suspicions...

Collapse
 
islam profile image
Islam Sayed

Really!
To this extent:)

Collapse
 
qm3ster profile image
Mihail Malo • Edited

You know what would be RADICAL?
Renaming this article to const, let, and... var, to comply with the the good, the bad, and the ugly formula.

Collapse
 
islam profile image
Islam Sayed • Edited

You made me laugh, Mihail

Collapse
 
qm3ster profile image
Mihail Malo

Did I? Or did I make you exhale audibly through your nose? :D

Thread Thread
 
islam profile image
Islam Sayed

If I wasn't at work, I would definitely do so :D

Thread Thread
 
qm3ster profile image
Mihail Malo • Edited

So, only laughing is allowed at work.
Got it.
salute

Hmm... animated GIFs work, but not PNGs?

Collapse
 
elharony profile image
Yahya Elharony

Great Article.
Thanks for sharing this with us, Islam!

Collapse
 
islam profile image
Islam Sayed

My dear friend, thank you.