ariya.ioAbout

ECMAScript 6 and Block Scope

4 min read

Until today, JavaScript comes with a function-level scope for variables and functions. This quirk often trips beginners who are already familiar with other curly braces language. With ECMAScript 6, the situation will change with the availability of the well-understood block scope.

Function-level scope leads to a situation called hoisting. For example, for this code:

function f() {
  doSomething();
  var a = 1;
}

what really happens is something like:

function f() {
  var a;
  doSomething();
  a = 1;
}

Often, the knowledge about hoisting (or lexical environment in general) is used in a quiz or an interview question. In the following fragment, those who don’t possess the understanding will be left puzzled:

console.log('foo' in window); // true
var foo;

For programmers familiar with C/C++/Java, the use of var in a wrong place can trigger many pitfalls, among others variable leaking. Whether this is intentional or not is often not cleared from the code itself. Ambiguity like that may lead to a bug and other hard-to-trace annoyances:

for (var i = ; i < 3; i++) {
  var j = i * i;
  console.log(j);
}
console.log(j); //  4

With the upcoming ECMAScript 6, we can solve the issue by using Let and Const Declarations, see Section 12.2.1 of the latest specification draft. If we rewrite the above example to use let, it will look like the following:

for (var i = ; i < 3; i++) {
  let j = i * i;
  console.log(j);
}
console.log(j); // will throw

then running it will give an error instead:

ReferenceError: j is not defined

This is the typical programmer’s expectation, j is confined to that particular curly-braced block.

Its partner-in-crime, const, behaves pretty much the same except it must be initialized and only once. This is perfect to store an immutable object. With both let and const, an optimistic static code analyzer can work much smarter to detect patterns which may cause problems and warn the user ahead of time.

When can we can start using let and const? Fortunately, we can already use it today. Firefox already has implemented some supports for ECMAScript 6, including this block scope. With Chrome, you can enable V8 experimental features by toggling the switch via chrome://flags.

Note: with V8, at least for the time being, you can use let with strict mode only, otherwise it will complain SyntaxError: Illegal let declaration outside extended mode.

What about other browsers? Until they start supporting this block scope feature, you need to fall back to the solution of converting the code (also known as transpiling) into some construct which can be executed by today’s browsers. Using a generic transpiler such as Google Traceur is often the recommended way.

An alternative solution is by using defs.js from Olov Lassus. The idea is to transform block scoped declarations into normal variable statements, obviously taking into account the scope of each declaration. Given the code, defs.js will use Esprima to parse the code, walk the syntax tree, and apply the transformation whenever necessary. As an example, this code fragment:

function f() {
  let j = data.length;
  console.log(j, 'items');
  for (let i = ; i < j; ++i) {
    let j = data[i] * data[i];
    console.log(j); // squares
  }
}

will be transformed into:

function f() {
  var j = data.length;
  console.log(j, 'items');
  for (var i = ; i < j; ++i) {
    var j$0 = data[i] * data[i];
    console.log(j$0); // squares
  }
}

Look how defs.js recognizes the right scope for j and therefore masquerade the innermost j with another name, j$0. The transformation itself is non-destructive, defs.js does not bother with anything other than let and const declaration. You can see how a comment is left untouched and the coding style is still exactly the same.

Obviously, there’s much more to defs.js than my simple example above, refer to Olov’s blog post for more details.

How do you plan to use let and const?

♡ this article? Explore other posts, browse the archives, or follow me Twitter.

Share this on Twitter Facebook Google+

comments powered by Disqus