The ultimate guide to variables in JavaScript
Veronika Šimić
Posted on January 30, 2023
It was a day of potato harvest. Working on the field all day isn't easy and you are ready to go home to your family. You sit down, sigh deeply, and enjoy a bit of fresh air.
Suddenly the king's herald appears.
"Hear ye, hear ye! His Majesty the King hereby declares that a new tax on all peasants, merchants and traders within the kingdom shall be imposed. The revenue from this tax shall be used to fund the king's big appetite. All merchants and traders are required to pay this tax in full, and failure to do so shall result in severe penalties."
Quickly you collect all potatoes and make a run for it. No way you are giving the potatoes you stole, fair and square, to some king. You end up in the woods and hide behind a big bush thinking:
"It would be nice to store all of this potatoes somewhere safe."
And just like that you hear a voice:
Hey you, those are some nice looking potatoes. Would you like me to take care of them?
Var
"Who is that? Show yourself before I throw one of my potatoes on you."
My name is var. I have been storing various things for peasants and kings for 20 years. But now it seems that the whole world has forgotten about me.
"Hmm... I'm kind of tired from carrying these potatoes. It would be nice to rest. Ok, var store them."
var potatoes = 20;
Thank you for this opportunity. Now if you want to retrieve them, just say the magic word console.log()
"Is there a way to protect them even more? It took me a long time to steal them."
How about this?
{
var potatoes = 20;
}
console.log(potatoes);
Output
20
"So, no? You ain't block scoped? How am I going to protect them then?"
I may not be block scoped but I am function scoped.
function protectPotatoes() {
var potatoes = 20;
}
console.log(potatoes);
Now, no one can access them. Even our great queen and king could not get them.
Output
ReferenceError: potatoes is not defined
In fact, I can even give them decoy potatoes and shadow your original potatoes.
var potatoes = 10;
function protectPotatoes() {
var potatoes = 20;
}
console.log(potatoes);
Output
10
"Ha! Does this happen because potatoes are globally scoped when they are defined outside the function? And now when they are inside the function, that is they are function scoped, they are only available inside that function block?"
Well, for a peasant, you sure do know a lot of JavaScript. For that, I'm going to show you what else I can do with your potatoes.
console.log(potatoes);
var potatoes = 20;
Output
undefined
You see, even though we haven't met yet, I believed in you. I knew you were going to bring me some potatoes. The way I see it is this:
var potatoes;
console.log(potatoes);
var potatoes = 20;
"Aha. So you are hoisted at the top? I can just declare that there are going to be some potatoes in the future. I don't need to assign anything yet? But there's just one thing I have been wondering. What if someone does this: "
var potatoes = 20;
var i = 1;
if (i > 0) {
var potatoes = 0;
}
console.log(potatoes);
Well, yes, now your potatoes aren't safe anymore. How are you only eating potatoes if you know so much JavaScript?
Output
0
"I think this isn't a very good trait of yours. You are quirky and untrustworthy."
What did you just say to me? Say goodbye to your precious potatoes.
var potatoes = 20;
var potatoes = 0;
console.log(potatoes);
Output
0
"Noooooooo, my potatoes. No wonder no one likes you. You can even redeclare."
Tell you what, if you can guess what's going to happen now, I'm going to bring your potatoes back.
console.log(potatoes);
function getPotatoes() {
var potatoes = 20;
console.log(potatoes);
}
getPotatoes();
console.log(potatoes);
"Well, I guess that I am having french fries for dinner! The correct answer is 20."
Ha. WRONG!!! What you get is nothing. You see, before the function is called, the first console.log(potatoes)
is executed. But since there are no potatoes yet, we get an error. Also, what are french fries?
Output
ReferenceError: potatoes is not defined
"Like I would tell you... thief!!"
Let 🌰
As you walk through the woods, defeated, hopeless and potatoless, you come across a tree of chestnuts.
After fighting a squirrel, you are faced with the same problem. A second voice appears:
Hail fellow, well met. Nice chestnuts you got there. What are you going to do with them?
"Who are you? var, is that you again? Get away from me!"
Oh easy there, my friend. I am not var. My name is let. I am var's cousin. I can store those chestnuts for you:
let chestnuts = 50;
"var did the same thing before she stole my potatoes. Now I am forced to eat chestnuts for dinner. I don't know if you noticed but I am not a squirrel."
Really? And what about those two very long front teeth? It's unfortunate that you ran into var. But I can assure you that I am different.
"Oh, really? And why should I trust you?"
Because I can protect your chestnuts:
{
let chestnuts = 50;
}
console.log(chestnuts);
Output
ReferenceError: chestnuts is not defined
"Now this is what I want. So you are block scoped, unlike that malicious var. What else can you do? Can you hide them inside a function?"
Well, yes that runs in our family.
function protectChestnuts() {
let chestnuts = 50;
}
console.log(chestnuts);
Output
ReferenceError: chestnuts is not defined
"And what about decoy chestnuts? Can you do something like this?"
let chestnuts = 10;
function protectChestnuts() {
let chestnuts = 50;
}
console.log(chestnuts);
Yes, I've also inherited this from var.
Output
10
"And what about this?"
console.log(chestnuts);
let chestnuts = 20;
Well, no I can't do that. I have to be sure there are chestnuts before I can show them to you. I am not as gullible as var.
Output
ReferenceError: Cannot access 'chestnuts' before initialization
"Aha. I guess you also don't have a problem with this:"
let chestnuts = 50;
let i = 1;
if (i > 0) {
let chestnuts = 0;
}
console.log(chestnuts);
Don't worry, even if someone has number 10, they won't be able to steal your chestnuts, I am block scoped, as you said.
Output
50
"There's got to be something wrong with you."
Well, yes there is, but I don't like talking about it. Since your teeth remind me of Mary, I'll tell you anyway.
"Who's Marry? Your mother?"
No, she was my rabbit. Anyway, I can't do this:
let chestnuts = 50;
let chestnuts = 0;
console.log(chestnuts);
Output
SyntaxError: Identifier 'chestnuts' has already been declared
"Aha, so you can't steal them. Hey, look, another chestnut. Please store this one as well."
let chestnuts = 50;
chestnuts += 1;
console.log(chestnuts);
Output
51
Well, now that I look at them, I want them for myself. While I can't redeclare, I can reassign.
let chestnuts = 51;
chestnuts = 0;
console.log(chestnuts);
Output
0
"Noooooo, you give them back. I thought we were friends. Don't I remind you of your rabbit?"
We ate that rabbit. Bye now.
Const 🍄
So here you are again, all alone in the woods, your stomach growling, potatoless, chestnutless. You walk down to the creek and find a bunch of mushrooms. Quickly, you take as much as you can and think:
"Although I like stealing, I don't like it when someone does it to me. Is there anyone I can trust?"
You hear another voice, which makes you wonder where all of these voices are coming from?
Yo, what's good y'all! It's your boy const, the one and only true variable straight outta JS. I'm here to spit fire and drop some knowledge.
"Can you store this for me and not steal it?"
Ha, I guess you've met var and let. Not very nice, are they? But don't worry.
const mushrooms = 15;
"And what if someone tries to do this?"
{
const mushrooms = 15;
}
console.log(mushrooms);
I got you, rabbit-man. Don't worry. Your mushrooms are safe.
Output
ReferenceError: mushrooms is not defined
"I have been cheated more than once. What about this?"
function protectMushrooms() {
const mushrooms = 15;
}
console.log(mushrooms);
No way, I ain't like that. I am guarding your 'shrooms. We good.
Output
ReferenceError: mushrooms is not defined
"So you are also block scoped. Can you do this: "
const mushrooms = 2;
function protectMushrooms() {
const mushrooms = 15;
}
console.log(mushrooms);
For sure. If you want them 'shrooms, tough luck.
Output
2
"And you can't steal them? What about reassigning and redeclaring?"
const mushrooms = 15;
const mushrooms = 0;
console.log(mushrooms);
const mushrooms = 15;
mushrooms = 0;
console.log(mushrooms);
Can't do that, ain't no way.
Output
SyntaxError: Identifier 'mushrooms' has already been declared
TypeError: Assignment to constant variable.
"Finally, I have found a friend. Oh look, another mushroom. Please store this one as well."
const mushrooms = 15;
mushrooms +=1
console.log(mushrooms);
I ain't with it, even for you, dawg, I'm out. I only keep values that don't change.
TypeError: Assignment to constant variable.
"What? I am deeply offended. Now I am starting to miss var and let."
You didn't just say that. Oh, I am hurt. I bet let and var didn't show you that we can do this:
const mushrooms = {
amount: 15,
};
mushrooms.amount = 0
console.log(mushrooms);
Output
{ amount: 0 }
"Nooooooooo. Not again. I thought you can't reassign values!"
Well, I can't except when it's objects. I kind of dig their vibe.
Wrap-Up
After a whole day's work, you go home potatoless, chestnutless, mushroomless.
Out of all the voices you've met, var is the most relaxed one, it's function scoped. Storing values inside var is not very safe since those values can be reassigned and redeclared.
Let is a little bit more rigid since it doesn't allow redeclaring but it does allow reassignment. It's block scoped just like const which is the strictest of them all. It doesn't allow redeclaring or reassigning, but it does have a soft spot for objects.
Very useful knowledge for a medieval peasant, don't you think? 🐰
Posted on January 30, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.