JavaScript Block Bindings and ES6 every developer must know!
Block Bindings
Usually bindings occur whenever we declare or set value in a variable. For example we use var, let and const to declare or assign a variable.
var a = 1;
let b = 2;
const c = 3;
This blog demonstrates how var and hoisting occurs and what are the best practices ES6 offers for block bindings using var, let and const.
Var Declarations and Hoisting
When variable declared with var they are hoisted to the top of the function or global scope if declared outside a function.
var declarations are treated as if they are hoisted to the top of the function (enclosing block) or to the global scope if they are declared outside a function. Consider the following function:
function getColor(condition) {
if (condition) {
var color = ‘green’;
return color;
} else {
// ‘color’ exists here with a value of undefined
return ‘color not found’;
}
// ‘color’ exists here with a value of undefined
}
You may expect the if condition is true then color variable will be created, but the ‘color variable is not dependent on any condition because of the hoisting nature of the var keyword. Behind the scene, javascript engine treats the function as follows:
function getColor(condition) {
var color;
if (condition) {
color = ‘green’;
return color;
} else {
return ‘color not found’;
}
}
From the above code it is clear that the color variable hoisted to the top even though the value of the variable stayed on the same spot. That’s why color variable is accessible within the else clause as well as within the function with undefined value.
Block-Level Declarations
We already learned the hoisting nature of var, which may create issues in some cases because of the accessibility of the variable. That’s why block-level declaration comes into picture where declare variables are inaccessible outside of a given block scope. Block scope can be created:
- Inside a function or function block
- Inside a block (wrapped with curly { } braces)
Variable declarations using let or const’ are not hoisted to the top of the enclosing block which can limit the variable’s scope to only the current code block. But if you want the variables are available to the entire block then you can declare the variable using let or const first in the block.
consider the same example but with **let**:
function getColor(condition) {
if (condition) {
let color = ‘green’;
return color;
} else {
// ‘color’ is not exists here
return ‘color not found’;
}
// ‘color’ is not exists here
}
so if let and const is used in block scope then hoisting will not occur but if var is used then hoisting will occur or variable will be accessible outside the block scope.
Block Binding in Loops
Block level is very useful when dealing with loops in javascript. It is best practice to use let instead of var because var is being hoisted. consider the following example:
for (var i = 0; i < 10; i++) {
// some code
}
// i is accessible here because we declare using var
console.log(i); // 10for (let i = 0; i < 10; i++) {
// some code
}
// i is inaccessible here because we declare using let
console.log(i); // error- i is not defined
Global Block Bindings
Global scope behavior for var is different than let and const. For example when var is used in the global scope, a new global variable is created, which is a property on the global object (window in browsers), but if you use let or const in the global scope, a new binding is created in the global scope but no property added to the global object (window in browsers). That mean for var you can accidentally overwrite an existing global, but if you use let or const you cannot overwrite. Here’s the example:
When var is being used:
// in a browser
var greeting = ‘Hello, Good Morning’;
console.log(window.greeting); // Hello, Good Morningvar person = ‘Hello there’;
console.log(window.person); // Hello there
When let is being used:
let greeting = ‘Hello, Good Morning’;
console.log(greeting); // Hello, Good Morning
console.log(window.greeting === greeting); // falseconst person = ‘Hello there’;
console.log(person); // Hello there
console.log(person in window); // false
Emerging Best Practices for Block Bindings
During ES6 development, the convention was to use let instead of var and use const to limit the modification. But as more developers migrated, developer following a convention that use const as default and use let when you know the variable value may change.
Functions in ES6
ES6 offers numbers of incremental improvements on the top of ES5 functions that make javascript less prone to error and more powerful.
Functions with Default Parameter Values
In ES5 and earlier requires lots of extra code to simulate default parameter value. ES6 make it easier to pass default parameter values when parameter is not formally passed when call the function. For example:
function add(num1, num2 = 0) {
//here, 0 is default parameter value
return num1 + num2;
}
console.log(add(20, 5)); // 25
console.log(add(20)); // 20
Working with Unnamed Parameters
Earlier in javaScript function parameters that are passed without defining are inspect through argument object. Though inspecting arguments works fine in most of the cases, this object can be a little cumbersome to work with. ES6 introduces the rest parameter to make it easier to work with unnamed parameters.
The rest parameter allows any number of arguments as an array.
function add(…args) {
// args is the name for the array
return args.reduce((accumulator, current) => accumulator + current, 0);
}console.log(add(5)); // 5
console.log(add(5, 3)); // 8
console.log(add(5, 2, 3)); // 10
The Spread Operator
Spread Operator takes in an iterable (e.g an array) and expands it to list of arguments.
The … spread operator is useful for many different tasks including following:
Copying an existing array
- Merge or combine arrays
- Call function without apply
- Use in Math Functions
- Use in destructuring
- Use array as arguments
- adding to state in React
- Convert arguments or NodeList to Array
Here are some of the code example:
// Using in Math
let arr = [6, 10, 21];
console.log(Math.max(…arr)); //21// Multiple iterable and combine
let arr1 = [25, -10, 31, 44];
let arr2 = [30, 26, 98, 11];
console.log(Math.max(…arr1, …arr2, 25)); //98// Combine or merge arrays
let arr3 = [33, 25, 21];
let arr4 = [28, 37, 35];
let combine = [10, …arr3, 20, …arr4];
console.log(combine);
// [ 10, 33, 25, 21, 20, 28, 37, 35 ]
Block-Level Functions
ES6 allows block-level functions which are hoisted on top of the function or hoisted into the global scope.. For example:
if (true) {
console.log(typeof doMath); // “function”function doMath() {
// some code
}doMath();
}console.log(typeof doMath); // function
Arrow Functions
ES6 allows an alternative way to write shorter syntax named arrow function compared to traditional function expression. For example:
// lets create function expression that add two numbers:
function add(a, b) {
return a + b;
}
console.log(add(21, 10)); //31// same function using arrow function syntax, where a and b are function parameter:
let add2 = (a, b) => a + b;
console.log(add2(21, 10)); // 31// above function can also be written as:
let add3 = (a, b) => {
return a + b;
};
console.log(add3(21, 10)); // 31// if only single parameter is required, parenthesis is not required
let square = (x) => x * x;
console.log(square(5)); // 25