If you started working with JavaScript before the release of ES2015, you are probably used to the fact, that JavaScript variables are function-scoped and hoisted etc.. With ES2015, you get a new way to define variables that are block-scoped.
Before ES2015
Back in the days var
was the keyword of choice to define a local variable, if you didn't use var
and used a new indentifier for assignment, you could create a global variable, sometimes even by accident, if you didn't use the "use strict";
statement.
function () {
// Global variable
newIdentifier = 5;
// Local variable
var variable = 6;
// Assignment to the defined variable
variable = 8;
// Another global variable (by accident)
varialbe = 8;
}
Your local variables were scoped by the function in which they were defined.
// You could write something like this:
function (x) {
if(x > 2) {
var y = 10 * x
}
return y
}
// But behind the scenes it would be treated as this:
function (x) {
var y
if(x > 2) {
y = 10 * x
}
return y
}
This lead many developers to define all the local variables at the top of the function, because they would end up there anyway.
Since ES2015
With the release of ES2015 JavaScript got many new features, one of them block scoped variables. There are two kind of them, let
and const
variables.
// So this wouldn't work:
function (x) {
if(x > 2) {
let y = 10 * x
}
return y
}
In the example, y
is only accessible inside the if-block, which is the default behavior of many other languages.
What this allows you to do is define variables where they are needed and scope them with code blocks.
// Every time you see a { and } you're creating a new block
// and in there you can create a new variable scoped to that block
while(...) {
let x = 10;
}
for(...) {
let x = 12;
}
if (...) {
let x = 9;
} else {
let x = 8;
}
try {
let x = 1;
} catch (e) {
let x = 99;
}
You can even use {}
on their own for scoping, to keep the vars as local as possible.
function () {
let varForTheWholeFunction = 10;
{
let scopedVar = getData();
varForTheWholeFunction = parse(scopedVar);
}
// scopedVar isn't accessible here
...
{
let scopedVar = filterData(varForTheWholeFunction);
varForTheWholeFunction = sortData(scopedVar);
}
return varForTheWholeFunction;
}
This can be used for switch
statements too.
function () {
let a;
switch(x) {
case "getData": {
let y = getData();
a = parse(y);
} break;
...
default: {
let y = "defaultData";
a = parse(y);
}
}
return a;
}
So what about const
? Well, their scoping works like with let
, but a value has to be assigned at definition time and it can't change later, only if the function, in which this local variable is declared, is called again.
function (x) {
if (x > 2) {
// This will fail:
const a;
// This will also fail:
const a = 1;
a = 2;
}
}
So it's a variable that can only be set once, but be careful:
function () {
// This would work:
const x = {y: 1};
x.y = 2;
}
Indirections aren't save from mutation.
Conclusion
With let
and const
JavaScript got a way to define scopes more fine granular, which enables developers to limit code dependencies even more.
The cost of this is added complexity to the language, but on the other hand, you don't have to use all of the features that exist :)
Top comments (6)
One can argue about this :) I would say that
let
andconst
makes Javascript simpler and thatvar
adds complexity to the language. Most developers expects variables to be blocked scoped. But then again you should really learn the language first and then the concept function scope shouldn't be a problem.I'm using a linting rule to disallow the use of
var
in my code base because i see no advantage of using it.On more case that is tricky with
var
is when deferring execution.var functions = [];
for (var i=0;i<3;i++) {
functions[i] = function(i) {
console.log(i);
}(i)
}
functions0; // 0
functions1; // 1
functions2; // 2
Nice post! If anyone needs any more clarifications on scopes, I really recommend reading this book here (free!) hosted on GitHub. It's a really nice read, a bit dense (lots of information, so read carefully!
github.com/getify/You-Dont-Know-JS...
Did you find any use cases where
var
is actually a good idea? Or is this keyword totally useless now thatlet
andconst
have been added?just compat reasons. If you want make something that runs in all browsers without compilation, you would go for var.
But I guess this is just a thing for tiny libs.
Good, simple explanation - thanks!