Everyone in the JavaScript world is talking about ECMAScript 6 (ES6, a.k.a. ES 2015) and the big changes coming to objects (`class`, `super()`, etc), functions (default params, etc), and modules (import/export), but less attention is being given to variables and how they are declared. In fact, some attention is being given, but perhaps without the right focus. I recently attended the jQuery UK conference where Dave Methvin gave a nice overview of ES6, with some great attention on `let` and `const`.

In this article I wanted to cover these two new keywords for declaring variables and differentiate them from `var`. And possibly more importantly, I want to identify what some folks are considering the new standard for declaring variables in ES6. The basic idea here is that `let` should, in time, replace `var` as the default declaration keyword. In fact, according to some, `var` should simply not be used at all in new code. The `const` keyword should be used for any variable where the reference should never be changed, and `let` for anything else.

Replacing `var` with `let`

This workflow shift may seem dramatic at first, but not as much when we think about the differences between `let` and `var`. While `var` creates a variable scoped within its nearest parent function, `let` scopes the variable to the nearest block, this includes `for` loops, `if` statements, and others.

function foo() {
  console.log( x );
  console.log( y );

  var x = 1;
  if (x === 1) {
    let y = 2;
  console.log( y );

console.log( x );

In the example above we create a new function (and var scope) with `foo` and then call the function. As expected, the last `console.log()` statement will produce a `ReferenceError` because `x` is only defined (scoped) inside the `foo()` function. The first console statement will execute just fine due to variable hoisting. In this case, `x` will evaluate to `undefined`. The second console statement, however, is more interesting. In fact, both of the `log(y)` calls will fail because the `let` keyword allows much tighter scoping than `var`. The `y` variable only exists inside of that `if` block, and no where else! Dave Methvin calls that area before the `let` declaration the “Temporal Dead Zone.”

Hopefully this example illustrates the specificity of `let`, but you may be saying that sometimes you actually want a function-scoped variable. No problem, simply create the variable at the top of your function!

function foo( x ) {
  let y;

  if (x === 1) {
    y = 2;
  console.log( y );

foo( 1 );
console.log( y );

The function above declares the `y` variable at the top of the function, thus giving it a larger scope than our first example. We can see that `y` is accessible anywhere inside this function, but not outside of it, that last `console.log(y)` statement will produce a `ReferenceError`. Before we move on to `const`, let’s reiterate our thesis: `let` should completely replace `var` in ES6. The examples above should show you that `let` is more powerful, while still allowing almost all of the flexibility of `var`. I’m not the first one to say it, but I’m a believer now.

Constant Reference, Not Value

The other new keyword for variable declaration in ES6 is `const`, but it is often misinterpreted as being a “constant value”. Instead, in ES6 a `const` represents a constant reference to a value (the same is true in most languages, in fact). In other words, the pointer that the variable name is using cannot change in memory, but the thing the variable points to might change.

Here’s a simple example. In the code below we create a new variable with a constant reference to an Array. We can then add values onto the array and since this does not change the reference, everything works:

const names = [];
names.push( "Jordan" );
console.log( names );

However, if we try to change the variable reference to a new array – even to one with the same contents – we will get a SyntaxError (“Assignment to constant variable”):

const names = [];
names = [];  // Error!

Of course, if you have a `const` that points to a primitive such as a string or number, then there really isn’t anything to change about that value. All methods on String and Number return new values (objects).

The last note about using `const` is that it follows the same new scoping rules as `let`! This means that between `let` and `const` we should be able to complete replace `var` in our code. In fact, there are many folks supporting the idea of only “allowing” `var` to be used in legacy code that hasn’t been touched. When a developer jumps into a file to update some code, they could (and possibly should) be updating all `var` statements to `let` or `const` as appropriate, with proper scoping.

But that’s just for ES6…

It’s true. The new `let` and `const` keywords are not available in ES5, and thus in most execution environments. However, with good transpilers such as Babel we can compile our ES6 JavaScript into runnable ES5 code for deployment to a browser environment.

Luckily for us Node.js (and io.js) developers we don’t have to worry about what browser someone is executing our JavaScript code in! If you’re using Node v0.12 (you are, right?), you can have access to these features with two small changes. First, you have to run your code with “harmony” features enabled (the original codename for ES6 was “harmony”):

~$ node --harmony /path/to/script

The second change is that any code using `let` or `const` (or any other ES6 feature) must be in strict mode. To do so, simply place `”use strict;”` at the top of every module. Alternatively, you could use the `–use-strict` flag on the CLI, but that may be a bit much.

In io.js you don’t need the `–harmony` flag because all of those features are being rolled right into the code. However, you do still need to make your code strict. Again, this can be done by simply placing a `”use strict”;` statement at the top of your module files.

1.0.0Are you using io.js? Wondering if StrongLoop supports it? We do! In addition to StrongLoop’s API platform being able to run on io.js, we also provide for our customers running on io.js.

Now go forth, and create a better variable declaration workflow!

What’s Next

  • Interested in more ES6 features? How about this post on Generators from Marc Harter?
  • If you’re curious what comes next after Node.js v0.12, check out this post from core contributor Bert Belder
  • And if you want to get started building APIs in Node.js with LoopBack, head over to our “Getting Started” page!