DEV Community

Cover image for let var be const
K
K

Posted on

let var be const

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;
    }
Enter fullscreen mode Exit fullscreen mode

It will actually be declared like that:

    function f(x) {
      var y;
      try {
        y = x.toString();
      } catch(e) {
        return "";
      }
      return y;
    }
Enter fullscreen mode Exit fullscreen mode

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;
    }
Enter fullscreen mode Exit fullscreen mode

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;
    }
Enter fullscreen mode Exit fullscreen mode

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;
    }
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

These on the other hand will:

    const a = [1, 2, 3];
    a.push(4);

    const b = {x: 10, y: 20};
    b.z = 30;
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

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)

Collapse
 
mortoray profile image
edA‑qa mort‑ora‑y

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.

Collapse
 
hrmny profile image
Leah • Edited

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.

Collapse
 
mortoray profile image
edA‑qa mort‑ora‑y

I'd like to note that C/C++ have both concepts, but usually refer to value constness.

T const * ptr = expr;

The T value is const here, not the pointer. This is usually what we want. Compare to:

T * const ptr = expr;

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++:

T const * const ptr = expr;

Read the type form right-to-left to understand where const applies (the syntax rules are a bit ugly for this in C).

Collapse
 
kayis profile image
K

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 use let or val.

Collapse
 
ben profile image
Ben Halpern

Nice explanation.

Collapse
 
kayis profile image
K

Thank you :)

Collapse
 
mattbidewell profile image
Matthew Bidewell

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!

Collapse
 
david_j_eddy profile image
David J Eddy

Very well done explanation! This cleared up so much for me.

Collapse
 
kayis profile image
K

Always happy to make people smarter :D