JavaScript can do lots of things; make desktop apps, run web servers, build world-class enterprise applications, make freakin' full-fledged games, and so much more. However, at each of these applications' core, there is data. And data is handled by variables. In this article, we'll be exploring JavaScript variables and how to use them properly.
Let's get right into it.
Variable Scope
Let's take a look at two programs:
// Example 1
{
var superImportantGovernmentPassword = "42";
}
// VS
// Example 2
{
let superImportantGovernmentPassword = "42";
}
If you're wondering why each of those variables are enclosed in curly brackets
{}
, just know that those curly brackets essentially act as a "container", restricting access to whatever's inside of them. However, as you'll soon see, that isn't always the case...
Let's say there's an evil programmer who got a copy of this code and wanted to publish it to the web for all of his criminal friends to see. He might do something like this:
publishSecretPassword(superImportantGovernmentPassword);
What'll happen next depends almost entirely on what variable keyword you used to declare superImportantGovernmentPassword
. You see, in one scenario, the code executed by the evil programmer will work as planned, but in the other case, he'll get this error:
ReferenceError: superImportantGovernmentPassword is not defined
Why is this happening?
It all has to do with variable scope, and how each keyword treats the data in the sense of that scope.
Scope Is A Container
Remember those curly brackets?
{
...
}
Well, in JavaScript, curly brackets are a way of blocking outside access to anything inside of these curly brackets. That's why, in one of the scenarios, the evil programmer gets a ReferenceError
back; because he , quite literally, couldn't touch superImportantGovernmentPassword
.
That's because of the fact that the superImportantGovernmentPassword
variable wasn't in the global scope. The global scope can be thought of as the place outside of the container. Anything outside of the container can be accessed by anybody! However, when you put something inside curly brackets, then you're adding a container to the field and putting something into that container. In our case, we're trying to put superImportantGovernmentPassword
in a safe scope so that people from the outside world can't access it.
But, what if I want to login to my secret FBI server?! I need my password! - A secret FBI agent
Well, we can fix that...
var
Negates Scope
As you've seen, we can block outside access by adding another scope to the program. However, things can get tricky when you use var
to declare your variables. Remember Example 1?
// Example 1
{
var superImportantGovernmentPassword = "42";
}
Well, if you were wondering which scenario lets the evil programmer complete his evil plan, this is it. That's because using var
completely negates any scope! Anything that is declared with the var
keyword gets put into the global scope, irrespective of where it was declared. You could put 100 nested curly brackets, and the evil programmer would still succeed.
It's for this reason that, as a general rule, JavaScript programmers...
NEVER USE var
TO DECLARE VARIABLES
I'll say it once more: NEVER USE var
TO DECLARE YOUR VARIABLES!
But, why? - You
Because it puts the functionality of your entire program, along with its readability, semantic meaning, and organization into a state of chaos. Imagine a program where every single function has access to every bit of data in your program; it would cause a lot of issues! For this reason, it is best practice to use the other two keywords we'll be talking about today: let
and const
.
How to NOT Negate Scope
Let's go back to Example 2:
// Example 2
{
let superImportantGovernmentPassword = "42";
}
Here, we use let
instead of var
. Now, if that evil programmer tries his dirty trick again, then he'll be met with this error:
ReferenceError: superImportantGovernmentPassword is not defined
This is because let
respects the scope it currently is working inside of, so it doesn't expose our superImportantGovernmentPassword
variable to the outside world. With that, we've beat the evil programmer and sent him back to his terminal shell. Neat.
Locking Values In
Let's say one of your top FBI officials is looking to login using that password. He executes his loginToSecretServer(password)
function, but comes up with an error:
Sorry! Wrong password. You have 2 more tries, then you're locked out. [This message was written by console.log()]
Since he knows the password is 42, he goes back to the file where the password is. Lo and behold, it is still 42:
...
let superImportantGovernmentPassword = "42";
...
What's causing the problem?
Well, he runs a find-and-replace through the repository and finds that superImportantGovernmentPassword
is referenced in another file. However, the code over there is a little fishy:
...
superImportantGovernmentPassword = "2408oifsd8fu08sdg";
...
He frowns. Somebody has changed the reference value of the variable, which meant that he was logging in with the WRONG password. He deletes the line of code, but also wants to prevent any future programmers from making the same mistake; how does he do that?
Well, observe what he does next:
/// Original password file
{
const superImportantGovernmentPassword = "42"; // NOTICE THE 'const'
}
Wait, what's const
? You see, const
is short for "constant", and when you declare a variable with it, it is essentially saying "The value of this variable will remain unchanged (or 'immutable') for as long as it's used". Thanks to this small change, the FBI officer can rest in peace, knowing that any foolish programmers who mistakenly try to change superImportantGovernmentPassword
's value indirectly will be met with this message:
TypeError: Assignment to constant variable.
Summary
So, let's summarize what we've learned:
- Never use
var
to declare variables, because it will let EVERY single part of your program access its value. Instead, uselet
, which respects the scope and prevents access to its value from outside the scope. - Scope is like a container; every program starts with a "global scope", where every variable lives by default as if it were in a "container". You can then create "sub-containers" to protect the values of some variables, which lets you prevent fatal errors in your program's logic!
- Sometimes, you don't want external sources changing the value of your variables. When you want that, use
const
, which locks in the value of your variable completely.
Thanks for reading. I hope you enjoyed!
Top comments (6)
It says on your profile that you are a learning web developer. I really like that you understand scopes but this is generally not a place where passwords are stored, especially not super important government ones. ;)
Oh, I completely understand! I was just using a pretty simple and impractical example to demonstrate the concept of scopes. I do not condone enclosing top-secret API keys, passwords, and other sorts of confidential information within the scope of an exposed program ;)
One day, maybe not today, maybe not tomorrow, this will become a normal thing as we move away from backends, or rather we smash the notion of servers. Clients will rule. That is my strange prediction.
That would be so weird but awesome at the same time. Write a blog post when it happens!
This is the sign that begs to differ.
Well? Where's Godzilla?!