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 vars 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
muti.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
Tvalue isconsthere, not the pointer. This is usually what we want. Compare to:The pointer is constant but the value is not. This is what
constappears 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
constapplies (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
constkeyword more like functional languages useletorval.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