10 Interesting hacks about JS (ES6) Block Bindings
Published: 2021-05-06 15:45:19

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
```

##  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)
}
```
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
}
```
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"
```

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
}
```

### 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
```


### 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); 
```

### 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
});
```
### 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
})
```
### 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);
    });
}
```
### 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!"
```
### 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.