DEV Community

loading...

10 Interesting hacks about JS (ES6) Block Bindings

Shamanta Sristy
I'm a MERN-stack Developer from Bangladesh who has a serious passion and dedication for building dynamic and responsive websites.
・4 min read

Today we are going to discuss an interesting topic of EcmaScript6(ES6), Block Bindings. This discussion is going to be about bindings variables to scope.

Binding?

Binding is the formal name of variables. When we declare and/or initialize a variable, we actually bind a value to a name inside a scope. And scope means to a specific part of a program.
So we bind a variable whenever we declare and/or initialize a variable using one of these keywords: var, let and const in JavaScript.

Example:

var a
let b
const last = c
Enter fullscreen mode Exit fullscreen mode

Hoisting

In short, hoisting is a mechanism that handles execution contexts in JavaScript. This means the variable and function declarations (not initializations) are put into the memory during the compile phases before going for any execution.

For example:

function getName(condition) {

var name

if (condition) {
name = 'Sherlock'
console.log(name)
}
else {
console.log(name)
}
console.log(name)
}
Enter fullscreen mode Exit fullscreen mode

From the above example, we can see, the declaration is hoisted to the top but the initialization is staying exactly where we type the name variable. This means that we can access the name variable from everywhere in the enclosing block in case of var binding.

Block Level Declarations

  • Inside a function (function block)
  • Inside a block (wrapped with two curly { } braces)

Let Declarations

We have already seen these block-level scopes in the example above. Now we will use the previous function again but this time using either let or const. So, we are using let :

function getName (condition) {

if (condition) {
let name = 'Nicholas'
console.log(name)
}
else {
// 'name' does not exists here
return null
}
// 'name' does not exists here
}
Enter fullscreen mode Exit fullscreen mode

At the let binding, we can see, name only exists inside the if block. It is not available outside the if block. Because JavaScript engine does not hoist let and const declarations. So the name is not accessible in else and enclosing blocks.

No Redeclaration

var name = "x"
//syntax error
let name = "y"
Enter fullscreen mode Exit fullscreen mode

In this example, name is declared twice: once with var and once with let.Because let will not redefine an identifier that already exists in the same scope, the let declaration will throw an error. On the other hand, no error is thrown if a let declaration creates a new variable with the same name as a variable in its containing scope, as demonstrated in the following code:
Example:

var count = 30;

// Does not throw an error
if (condition) {

    let count = 40;

    // more code
}
Enter fullscreen mode Exit fullscreen mode

Constant Declarations

You can also define variables in ES6 with the const declaration syntax. Variables declared using const are considered constants, meaning their values cannot be changed once set.

Constants vs Let Declarations

Constants, like let declarations, are block-level declarations. That means constants are destroyed once execution flows out of the block in which they were declared, and declarations are not hoisted, as demonstrated in this example:

if (condition) {
    const maxItems = 5;

    // more code
}

// maxItems isn't accessible here
Enter fullscreen mode Exit fullscreen mode

Block Binding in Loops

Perhaps one area where developers most want block-level scoping of variables is within for loops, where the throwaway counter variable is meant to be used only inside the loop. For instance, it's not uncommon to see code like this in JavaScript:

for (var i=0; i < 10; i++) {
    process(items[i]);
}

// i is still accessible here
console.log(i); 
Enter fullscreen mode Exit fullscreen mode

Functions in Loops

The characteristics of var have long made creating functions inside of loops problematic because the loop variables are accessible from outside the scope of the loop. Consider the following code:

var funcs = [];

for (var i=0; i < 10; i++) {
    funcs.push(function() { console.log(i); });
}

funcs.forEach(function(func) {
    func();     // outputs the number "10" ten times
});
Enter fullscreen mode Exit fullscreen mode

Let Declarations in Loops

A let declaration simplifies loops by effectively mimicking what the IIFE does in the previous example. On each iteration, the loop creates a new variable and initializes it to the value of the variable with the same name from the previous iteration. That means you can omit the IIFE altogether and get the results you expect, like this:

var funcs = [];

for (let i=0; i < 10; i++) {
    funcs.push(function() {
        console.log(i);
    });
}

funcs.forEach(function(func) {
    func();     // outputs 0, then 1, then 2, up to 9
})
Enter fullscreen mode Exit fullscreen mode

Constant Declarations in Loops

The ECMAScript 6 specification doesn't explicitly disallow const declarations in loops; however, there are different behaviors based on the type of loop you're using. For a normal for loop, you can use const in the initializer, but the loop will throw a warning if you attempt to change the value. For example:

var funcs = [];

// throws an error after one iteration
for (const i=0; i < 10; i++) {
    funcs.push(function() {
        console.log(i);
    });
}
Enter fullscreen mode Exit fullscreen mode

Global Block Bindings

Another way in which let and const are different from var is in their global scope behavior. When var is used in the global scope, it creates a new global variable, which is a property on the global object (window in browsers). That means you can accidentally overwrite an existing global using var, such as:

// in a browser
var RegExp = "Hello!";
console.log(window.RegExp);     // "Hello!"

var ncz = "Hi!";
console.log(window.ncz);        // "Hi!"
Enter fullscreen mode Exit fullscreen mode

Emerging Best Practices for Block Bindings

While ES6 was released, developers thought let should behave exactly as var did. So, the direct replacement makes logical sense. In this case, you would use const for variables that needed modification protection
However, as more developers migrated to ECMAScript 6, an alternate approach gained popularity: use const by default and only use let when you know a variable's value needs to change.

Discussion (0)