Cover image by Christiaan Colen on Flickr
With ES2015 JavaScript got a bunch of new features, two of them being let
and const
keywords that let you declare your local variables.
var
Variables you declare with var
will be scoped to the function they were declared in.
This means, even if you declare them in nested blocks (other curly braces) inside of a function, they will still be scoped to the function.
For example, if you declare it inside of a try block like this:
function f(x) {
try {
var y = x.toString();
} catch(e) {
return "";
}
return y;
}
It will actually be declared like that:
function f(x) {
var y;
try {
y = x.toString();
} catch(e) {
return "";
}
return y;
}
Every var
declaration will be hoisted to the top of the function. This is why it is considered a best practice
to declare var
s at the top of a function, it will end up there anyway.
If you want to scope a var
to a code block, you would have to fill or replace it with a function expression and call the function right after definition.
function f(x) {
var y;
if (x >= 0) (function() {
var z = Math.random() * 10;
y = x * z;
})();
return y;
}
The anonymous function has access to f()
s local variables, so it can use y
, but z
is only defined inside of the anoynmous function and can't be accessed inside f()
.
As you can see, this is rather sub-optimal, but this was the way for many years. If you are bound to use ES5 and for some reason can't use a compiler like Babel, you still have to do this.
let
The let
keyword is now a way to declare variables that aren't scoped to a function, but to a block. This means any code enclosed by curly braces confines that variable.
function f(x) {
let y;
if (x >= 0){
let z = Math.random() * 10;
y = x * z;
} else {
y = 10;
}
return y;
}
In this example z
is only accessible inside the if
-branch, the else
branch or the rest of f()
could not access it.
Blocks can alse be used without any statement.
function f(x) {
let results = [];
// first calculations
{
let a = 10 * 10 * x;
let b = a * Math.PI;
results.push(b);
}
// second calculations
{
let a = 3 + 2 + x;
let b = a * a;
let c = a + b;
results.push(c);
}
return results;
}
This allows to structure code and scope variables to the part of the function they are used. As you can see, the blocks have access to the outer scope variables results
and x
.
const
So what is the const
keyword about? Well, you may have seen it in other languages like C or Java. In JavaScript it declares a variable that can't be changed, but be careful this only applies to the direct content of that variable. Otherwise it scopes as let
.
This won't work:
const a = 10;
a = 11;
These on the other hand will:
const a = [1, 2, 3];
a.push(4);
const b = {x: 10, y: 20};
b.z = 30;
To prevent objects (arrays are objects too) from being changed, you need to freeze
them manually
, which impacts performance.
This will throw an error:
const a = Object.freeze([1, 2, 3]);
a.push(4);
When Use What?!
I try to use const
as much as possible, if functions get bigger, it often gets cumbersome to find out how often and where a variable was changed on the way down.
Sometimes it helps to use let
with try/catch
, because I have to set a variable inside try
and it needs to be accessible after the try
.
I avoid var
completely nowadays. const
and let
have the same scoping, their only difference is their write-access, so it's easy to reason about them interchangably. var
on the other hand works much different from them and I think it just makes stuff more complicated when mixed.
Top comments (9)
Good explanation of
const
. Though I find it really unfortunate that so many languages are adding this somewhat broken definition of what it means to be constant. In practice, a constant binding between a name and a value object isn't that helpful. I want actual constant value objects, not names.Rust has actual constants and is immutable by default.
To make a variable mutable you add
mut
i.e.let mut number = 5;
If you don't add it and change it later in the code the compiler will throw an error.
This also applies to methods that change something in a vector (list) or a hashmap.
I'd like to note that C/C++ have both concepts, but usually refer to value constness.
The
T
value isconst
here, not the pointer. This is usually what we want. Compare to:The pointer is constant but the value is not. This is what
const
appears to mean in JavaScript, which is misleading based on it's syntax.You can have both at the same time in C/C++:
Read the type form right-to-left to understand where
const
applies (the syntax rules are a bit ugly for this in C).Yes, I find this approach strange too.
I mean it looks like a constant, but it is re-assinged every call of the function it is declared.
I would expect a constant to be defined statically, like classes in most languages.
You have a module, it has constants, they are declared at import time, they can only be created with literals and other constants and this is it.
JavaScript uses the
const
keyword more like functional languages uselet
orval
.Nice explanation.
Thank you :)
RALLY YOUR BANNERS PEOPLE!
DEATH TO VAR!
(Imaginary medieval battle of Const of Let joining forces to take down var.)
Haha,
Coming from a Java background, this and Async/Await are some of the best features JS has brought in. Now I'm full-time JS, I love programming with it!
Very well done explanation! This cleared up so much for me.
Always happy to make people smarter :D