ES6
ES6 refers to version 6, of the ECMAScript which is a JavaScript standard meant to ensure the interoperability of Web pages across different Web browsers. It was published in June 2015, therefore you might find it renamed as ES2015.
It is a major enhancement to the JavaScript language and adds many more features intended to make large-scale software development easier.
Along with these, it brings a so-called syntactical sugar, which is syntax with the same behavior but designed to make things easier to read or to express.
var vs. let vs. const
The main difference between var
and let
is that instead of being function scoped, let
is block scoped. What that means is that a variable created with the let
keyword is available inside the “block” that it was created in as well as any nested blocks. “Block”, means anything surrounded by a curly brace {}
like in a for
loop or an if
statement.
{
var globalVar = "Hello globalVar"
}
{
let globalLet = "Hello globalLet";
}
console.log(globalVar)
console.log(globalLet)
let
declarations are not hoisted.
let me = "go"; // locally scoped
var i = "able"; // globally scoped
console.log(window.me);
console.log(window.i);
//Function Scope
function loop() {
for( var i = 0; i < 5; i++) {
console.log(i);
}
console.log(i)
}
//Block Scope
function loop2() {
for( let i = 0; i < 5; i++) {
console.log(i);
}
console.log(i)
}
loop()
loop2()
const
prevents redeclaring the same variable
const x = 5
x = 8 //throws error
const obj = {
firstName: 'Mihai',
lastName: 'Gheorghe'
}
obj.firstName = 'Bogdan'
obj //doesn't throw an error due to difference between
//pass by value vs. pass by reference
=== vs ==
the 3 symbol comparison operator ===
or !==
adds a type check between the two operands
let x = 5
x === '5' //evaluates to false
x === 5 // evaluares to true
x == '5' // evaluares to true
x == 5 // evaluares to true
You can find more about how comparison operators evaluate in various scenarios at the following link:
https://dorey.github.io/JavaScript-Equality-Table/
Arrow functions
Arrows functions are both syntactical sugar and have a structural impact on how the code is being executed.
An arrow function expression is a compact alternative to a traditional function expression, but is limited and can't be used in all situations.
The { }
and ( )
and return
are optional, but may be required.
For example, if you have multiple arguments or no arguments, you'll need to re-introduce parentheses around the arguments.
// Traditional Function
function simpleCalc(a){
return a + 100;
}
// Arrow function
a => a + 100
const simpleCalc = b => b + 100 //named arrow functions
var sum = (a, b) => {
let c = 40;
return a + b + c;
}
An arrow function does not have its own bindings to this
or super
, and should not be used as methods.
var cat = {
lives: 9,
jumps: () => {
this.lives--;
}
}
cat.jumps()
cat.lives //returns 9
var cow = {
lives: 1,
jumps: function() {
this.lives--;
}
}
cow.jumps()
cow.lives //returns 0
Template literals
Template literals are string literals allowing embedded expressions. You can use multi-line strings and string interpolation features with them.
They were called "template strings" in prior editions of the ES2015 specification.
console.log(`string text line 1
string text line 2`);
They allow also simple evaluations using the ${ eval } syntax.
let a = 5;
let b = 10;
console.log(`Fifteen is ${a + b}`)
this keyword
In JavaScript this
is a special keyword and it basically refers to the object it belongs to. It was used before ES6 too but the introduction of arrow functions changes its behavior. this
is an implicit parameter, that is when every execution context is created, this
is automatically added to the local scope as a parameter with the value of what is on the left-hand side of .
- calling function. If the "dot" is missing when calling the function, it will default to the global object.
However, it has different values depending on it is used:
In a method,
this
refers to the owner object. If the method's syntax is written with an ES6 arrow function, then it refers to the enclosing scope of the owner object. In other words, in arrow functions,this
is lexically scoped, meaning it refers to the object where the function was declared, not the called.In the global scope or in a function,
this
refers to the global object. However, usingstrict mode
,this
isundefined
.In an event, such as a DOM
onclick
, it refers to the element that received the event.Core function methods such as
call()
,apply()
orbind()
can referthis
to any object passed as an argument.
var person = {
firstName: "John",
lastName : "Doe",
id : 5566,
fullName : function() { //fullName is a method of person
return this.firstName + " " + this.lastName;
}
};
person.fullName() //returns "John Doe"
// In web browsers, the window object is also the global object:
console.log(this === window); // true
a = 37;
console.log(window.a); // 37
this.b = "MDN";
console.log(window.b) // "MDN"
console.log(b) // "MDN"
var globalObject = this;
var foo = (() => this);
console.log(foo() === globalObject); // true
<button onclick="alert(this.tagName.toLowerCase());">
Show this
</button>
.call()
The call()
method calls (executes) a function with a given this
value and arguments provided. In practice, it is used to write methods that can be reused on different objects. Both this
and additional arguments are optional.
function Product(name, price) {
this.name = name;
this.price = price;
}
function Food(name, price) {
Product.call(this, name, price); //the new Food object is called on
this.category = 'food'; // a method of Product and args are passed as well
}
console.log(new Food('cheese', 5).name);
// expected output: "cheese"
let person = {
age: 23,
incrementAge: function() {
const add1 = () => { this.age++ }
add1.call(this) //using add1() would have set "this" to "global object"
// this way "this" available in the incrementAge method is passed to
// the arrow function add1
}
}
.apply()
This methods is similar to call()
, the only difference is that the arguments are passed as an array. The method is quite useful even if this
is not passed, in scenarios where we need to pass an unknown or large number of arguments.
const array = ['a', 'b'];
const elements = [0, 1, 2];
array.push.apply(array, elements); //push accepts a variable number of arguments
console.info(array); // ["a", "b", 0, 1, 2]
.bind()
This method is also similar, meaning it takes this
and additional arguments but returns a new function, which is not executed at that point.
var person = {
name: 'John'
}
function sayTo(first, second){
return first + ' ' + this.name + second;
}
var sayToPerson = sayTo.bind(person);
sayToPerson('Hi', '. How are you?') //Hi John. How are you?
Spread operator and Rest parameters
The spread operator ...
allows an iterable variable or expression to be expanded for scenarios where more arguments are expected.
function sum(x, y, z) {
return x + y + z;
}
const numbers = [1, 2, 3];
console.log(sum(...numbers));
// expected output: 6
// it basically replaces the following use of apply
console.log(sum.apply(null, numbers));
// expected output: 6
let arr = [1, 2, 3];
let arr2 = [...arr]; // like arr.slice()
arr2.push(4);
// arr2 becomes [1, 2, 3, 4]
// arr remains unaffected
let arr3 = [19, 15, -5];
arr = [...arr, ...arr3] //it can be used multiple times
// arr is now [1, 2, 3, 19, 15, -5]
ES6 Utility functions
ES6 introduced, among many other features, a set of utility functions that we'll find very useful for writing functional programming code. Here are some of them:
.forEach()
This is an array method, explicitly Array.prototype.forEach()
, that executes a provided (callback) function once for each array element. The callback takes the following arguments in order: current value, index of the current value, and the whole array. The last two are optional.
forEach()
returns undefined
const array1 = ['a', 'b', 'c'];
array1.forEach( (value, index, arr) => {
console.log(`${value} pe pozitia ${index} din ${arr.length} pozitii`)
});
// expected output: "a pe pozitia 0 din 3 pozitii"
// expected output: "b pe pozitia 1 din 3 pozitii"
// expected output: "c pe pozitia 2 din 3 pozitii"
.map()
This is a method similar to .forEach() but instead, it returns a new array, of the same length as the one called upon, where each element is the result of the callback function.
let numbers = [1, 4, 9]
let roots = numbers.map(function(num) {
return Math.sqrt(num)
})
// roots is now [1, 2, 3]
// numbers is still [1, 4, 9]
Another shorthand example to create a new array containing the square of each element of the original array:
const originalArray = [1, 2, 3, 4, 5];
const squaredArray = originalArray.map(x => x * x);
console.log(squaredArray); // [1, 4, 9, 16, 25]
.filter()
Array.prototype.filter()
also takes a callback function as an argument but this tests each element of the array. It returns a new array, possibly of smaller length, containing only the elements that passed the test.
function isBigEnough(value) {
return value >= 10 //although the callback returns boolean,
//filter returns an array of elements
}
let filtered = [12, 5, 8, 130, 44].filter(isBigEnough)
// filtered is [12, 130, 44]
.reduce()
This method is a bit more complex, but also very powerful. It accumulates the result of a callback function over each element of the array. In other words, it reduces that array to a single value.
The callback takes the following arguments: the accumulator, the current value being iterated, and optionally the index of the current value and the array itself.
The method takes, along the callback, an additional argument which will be considered the initial value of the accumulator.
const array1 = [1, 2, 3, 4];
const reducer = (accumulator, currentValue) => accumulator + currentValue;
// 1 + 2 + 3 + 4
console.log(array1.reduce(reducer));
// expected output: 10
// 5 + 1 + 2 + 3 + 4
console.log(array1.reduce(reducer, 5));
// expected output: 15
//under the hood basic simulation of .reduce()
const reduce = function(collection, callback, initialValue) {
let accumulator = initialValue
for (let i = 0; i < collection.length; i++) {
if (i === 0 && initialValue === undefined) {
accumulator = collection[0]
} else {
accumulator = callback(collection[i], accumulator)
}
}
return accumulator
}
reduce([1,2,4], (v, sum) => v + sum, 0)
//in this case the arrow function is the callback
More examples of ES6 utility functions
Array.from() converts an iterable object to an array.
Array.find() returns the first element in an array that satisfies a condition.
Array.findIndex() returns the index of the first element in an array that satisfies a condition.
Array.includes() checks if an array contains a specific element.
Array.some() checks if any element in an array satisfies a condition.
Object.assign() copies the properties of one object to another object.
Object.keys() returns an array containing the names of all of the properties of an object.
Object.values() returns an array containing the values of all of the properties of an object.
Object.entries() returns an array containing two-element arrays, where each element is a property name and value from the original object.
Math.max() returns the largest number of a given set of numbers.
Math.min() returns the smallest number of a given set of numbers.
Math.floor() rounds a number down to the nearest integer.
Math.ceil() rounds a number up to the nearest integer.
Math.round() rounds a number to the nearest integer.
Last updated
Was this helpful?