let variables are block-scoped, meaning that they can only be accessed within the block in which they are declared.
const variables are also block-scoped, but they are also immutable, meaning that their values cannot be changed.var variables are function-scoped, meaning that they can be accessed anywhere within the function in which they are declared, even within nested blocks.let and constlet and const variables offer several benefits over var variables:
let, const, and varlet to declare a variable that you need to reassign within a block.const to declare a variable that you do not need to reassign within a block.var to declare a variable that you need to access globally.Basic syntax:
In ES5, when using double or single quotes, strings must be completely contained on a single line. There are workarounds for this shortcoming.
Workarounds with join and \n.
In ES6, template literals make multiline strings easy.
All whitespaces inside the backticks are parts of the string, so be careful with indentation.
Another Example:
${ and a closing } that can have any JavaScript expression inside.var term = "Keeravani";
const url = `https://itunes.apple.com/search?term=${term}&media=music&limit=20`;
console.log(url);
// => https://itunes.apple.com/search?term=keeravani&media=music&limit=20
var a = 10;
var b = 10;
console.log(`The number of JS MVC frameworks is
${2 * (a + b)} and not ${10 * (a + b)}.`);
// => The number of JS frameworks is 40 and not 200.The ${} works fine with any kind of expression, including member expressions, function and method calls.
Advanced example of building HTML structures.
var li = (obj) => `<li><a href="${obj.url}">${obj.label}</a></li>`;
var ul = (arr) => `<ul>${arr.map((obj) => li(obj)).join('\n')}</ul>`;
var arr = [
{url: "http://www.twitter.com", label: "Twitter"},
{url: "http://www.linkedin.com", label: "Linked In"},
{url: "http://www.facebook.com", label: "Facebook"}
];
document.getElementById('list').innerHTML = ul(arr);This will generate the following output:
Destructuring in ECMAScript 6 enables the same syntax for extracting data. Just as the object literal lets us create multiple properties at the same time, the object pattern lets us extract multiple properties at the same time.
ES5 equivalent
Only for object literals: If the value of a property is provided via a variable whose name is the same as the property name, you can omit the property name.
This declaration is equivalent to:
You can also pull properties as deep as you want.
ES5 equivalent
Destructuring works for arrays as well. How? By using square brackets in the destructuring side of the declaration.
The rest operator lets you extract the remaining elements of an array into an array. You can only use this operator as the last part inside an array.
Attention: The same syntax (…) is used by the spread operator!
If you destructure an object, you mention only those properties that you are interested in.
If you destructure an array, you can choose to only extract a prefix.
You can also conveniently skip over elements that you don’t care about.
We can also mix objects and arrays together and use theirs literals.
The same with return value of a function:
If the value of a destructuring assignment isn’t match, it evaluates to undefined. Just like when accessing not defined properties on an object with the dot or bracket notation.
Example of deep objects:
Question: What are the values of variables x and y?
If you’re trying to access a deeply nested property of a parent that doesn’t exist, then you’ll get an exception.
It makes sense if you rewrite destructuring in ES5:
If a part (an object property or an array element) has no match in the source, it is matched against:
Providing a default value is optional. Example with array:
Explanation: The element at index 0 has no match on the right-hand side. Therefore, destructuring continues y matching x against 3, which leads to x being set to 3.
Example with object:
undefined triggers default values. Default values are also used if a part does have a match and that match is undefined.
Default values are computed when they are needed (on demand). This
is equivalent to
So far we have only seen default values for variables, but you can also associate them with object itself:
What does this mean? The element at index 0 has no match, which is why destructuring continues with:
Another example with complex default values:
You can also use destructuring in a function’s parameter list.
Next advanced example:
Computed property names are another object literal feature that also works for destructuring. You can specify the name of a property via an expression, if you put it in square brackets.
If we try to omit var, let or const, it will throw an error, because block code can’t be a destructuring assignment.
Solution: We have to wrap it in parentheses.
No return keyword is required with a single statement.
There is a special case - an arrow function that wants to return an object literal {...}. In this case, the function body must wrap the literal in parentheses.
Immediately-invoked function expressions (IIFEs) allow you to define an anonymous function and call it immediately without saving a reference.
function Car () {
this.fuel = 0;
this.distance = 0;
}
Car.prototype.move = function () {
if (this.fuel < 1) {
throw new RangeError('Fuel tank is depleted')
}
this.fuel--
this.distance += 2
}
Car.prototype.addFuel = function () {
if (this.fuel >= 60) {
throw new RangeError('Fuel tank is full')
}
this.fuel++
}
var car = new Car();
car.addFuel();
car.move();Important notes:
class keyword followed by the name of the class.fuel and distance.for...in loop over the object or use Object.keys() to get an array of property names. But you can iterate over class methods by Object.getOwnPropertyNames(MyClass.prototype).new throws an error.Classes and functions are similar in that they have two forms: declarations and expressions. - Function and class declarations begin with an appropriate keyword (function or class, respectively) followed by an identifier. - Functions have an expression form that doesn’t require an identifier after function, and similarly, classes have an expression form that doesn’t require an identifier after class.
The previous example used an anonymous class expression. The name property of PersonClass (PersonClass.name) is an empty string. When using a class declaration, PersonClass.name would be "PersonClass".
A named class expression includes an identifier after the class keyword.
The PersonClass2 identifier exists only within the class definition. It is defined for use only inside the class. Outside the class, typeof PersonClass2 is undefined because no PersonClass2 binding exists there.
Another interesting use of class expressions is creating singletons by immediately invoking the class constructor. To do so, you must use new with a class expression and include parentheses at the end.
Classes make inheritance easier to implement by using the familiar extends keyword.
Derived classes require you to use super() if you specify a constructor; if you don’t, an error will occur. If you choose not to use a constructor, then super() is automatically called for you with all arguments upon creating a new instance of the class. For instance, the following two classes are identical:
Important notes:
super() in a derived class. If you try to use it in a non-derived class (a class that doesn’t use extends), it will throw an error.super() before accessing this in the constructor. Attempting to access this before calling super() results in an error.The methods on derived classes always shadow methods of the same name on the base class.
You can also call the base class version of the method by using the super. E.g.
In ES5 and earlier, it was not possible to inherit from built-ins like Array, RegExp, etc. It is possible in ES6.
Any method that returns an instance of the built-in will automatically return a derived class instance instead. So, if you have a derived class called MyArray that inherits from Array, methods such as slice() return an instance of MyArray.
We have the ability to define getters and setters for our fields. This feature allows to access the fields as any other object property.
When we define a getter and no setter, the variable with the getter / setter name becomes read-only.
Adding additional methods directly onto constructors to simulate static members is a common pattern in ES5 and earlier.
ES6 classes simplify the creation of static members by using the static annotation before the method or accessor property name.
One thing you can do in JavaScript but can’t in Java: from the derived class you can override and call your parents static method.
There are no static fields in ES6, but there is a discussion about it for ES7. Right now you can simulate the functionality like this:
This concept is not implemented in ES6 or ES7, but we can simulate abstract classes. We can use new.target in class constructors to determine the constructor the class is being instantiated with.
// abstract base class
class Shape {
constructor() {
if (new.target === Shape) {
throw new Error("This class cannot be instantiated directly.")
}
}
}
class Rectangle extends Shape {
constructor(length, width) {
super();
this.length = length;
this.width = width;
}
}
var x = new Shape(); // throws error because new.target is Shape
var y = new Rectangle(3, 4); // no error, new.target is RectangleThis concept is not implemented too, but we can mimic abstract methods.
class Abstract {
constructor() {
if (this.method === undefined) {
throw new TypeError("Must override method");
}
}
}
class Derived1 extends Abstract {}
class Derived2 extends Abstract {
method() {}
}
const a = new Abstract(); // this.method is undefined; error
const b = new Derived1(); // this.method is undefined; error
const c = new Derived2(); // this.method is
// Derived2.prototype.method; no error Private fields are not supported in any ES right now, but there are a couple of new structures in ES6 that let you emulate the private scope.
Warning: The above WeakMap is shared among all Warrior instances, so potentially you can access another warrior’s health.
This functionality have never existed in JavaScript and there is no plan on supporting it. If you have e.g. three methods of the same name say
the last say() method wins (overwrites all other).
JavaScript has no type checking on arguments or required quantity of arguments, so you can just have one implementation of say().
There is no concept of interfaces in any version of JavaScript.
You can find interfaces in TypeScript.
export.import.export in front of any variable, function or class export it from the module.
Declare a variable, function or class and export it later.
Can use the as keyword to specify a new name for importing.
There may be a time when you’d like to re-export something that your module has imported. Use cases: - You’re creating a library out of several small modules. - Modules extend other modules, and partially expose some of their features.
Note: If you’d like to export everything from another module, you can use the * pattern.
Once you have a module with exports, you can access the functionality in another module by using the import keyword.
Import the entire module as a single object.
If the module importing a variable, function or class wants to use a different name, it can use as.
Example:
Note: There is no identifier named add in this module.
default keyword,import statement.A module can import things from other modules.
'../model/user') relatively to the location of the importing module. The file extension can usually be omitted.'/lib/js/helpers') which point directly to the file of the module to be imported.'util'). What modules names refer to has to be configured. A typically configuration in JavaScript projects refers to the node_modules directory as root.// import a module without any import bindings
import 'jquery';
// import the default export of a module
import $ from 'jquery';
// import a named export of a module
import { $ } from 'jquery';
// import a named export to a different name
import { $ as jQuery } from 'jquery';
// import an entire module instance object
import * as crypto from 'crypto';
// export a named function
export function foo() {};
// export the default export as a function
export default function foo() {};
// export an existing variable
export { encrypt };
// export a variable as a new name
export { decrypt as dec };
// export an export from another module
export { encrypt as en } from 'crypto';
// export all exports from another module
export * from 'crypto';To support modules, the module value was added as a type option of the script element. Setting type to module tells the browser to load any inline code or code contained in the file specified by src as a module.
The Promise object represents the eventual completion (or failure) of an asynchronous operation and its resulting value.
A Promise is in one of these states:
fetch(`https://itunes.apple.com/search?term=${term}&media=music&limit=20`)
.then(res => {
return res.json()
.then(data => {
console.log(data)})
.catch(err => { alert(err) })})// This will handle if any error happens while converting res->JSON
.catch(err => { alert(err) }) //This will handle any fetch invocation errors
In ECMAScript 5 and earlier, there is the following pattern to create a function with default parameters values:
timeout and callback are optional parameters that get default values if they are not provided.|| always returns the second operand when the first is falsy.This approach still requires a lot of extra code for a very basic operation. ECMAScript 6 makes it easier!
This function only expects the first parameter to always be passed. The other parameters have default values.
Examples how the function can be called:
In the case of default parameter values, a value of null is considered to be valid.
arguments object remains detached from the named parameters.
The outputs:
The default value need not be a simple value. It can be any valid expression, even a function to retrieve the default parameter value.
Important: The default value expressions are lazily evaluated, meaning they’re only run when they’re needed (when a parameter’s argument is omitted or is undefined).
You can use a previous parameter as the default for a later parameter.
The formal parameters in a function declaration are in their own scope. A reference to an identifier in a default value expression first matches the formal parameters’ scope before looking to an outer scope. Example:
The w in the w + 1 default value expression looks for w in the formal parameters’ scope, but does not find it, so the outer scope’s w is used. Next, the x in the x + 1 default value expression finds x in the formal parameters’ scope, and luckily x has already been initialized, so the assignment to y works fine.
However, the z in z + 1 finds z as a not-yet-initialized-at-that-moment parameter variable, so it never tries to find the z from the outer scope and throws a ReferenceError.
ES6 introduces a new ... operator that’s typically referred to as the spread or rest operator, depending on where/how it’s used. When ... is used in front of an iterable (Array, Set, Map, …), it acts to “spread” it out into its individual values.
A typical usage: Specify an array, split it into items which are passed in as separate arguments to a function.
ES5 way:
That means, the spread operator acts as a simple syntactic replacement for the apply() method.
The spread operator can be used to spread out a value in other contexts as well, such as inside another array declaration:
Here, ... is replacing concat(), as it behaves like [1].concat(a, [5]).
Another example for mixing the spread operator with other arguments:
ES5 equivalent:
The other common usage of ... can be seen as the opposite - instead of spreading a value out, the ... gathers a set of values together into an array.
The ...z in this snippet is saying: “gather the rest of the arguments (if any) into an array called z”.
The ...z is called rest parameters because you’re collecting the rest of the parameters.
The rest parameters can be used as a better alternative to arguments (arguments is not really an array, but an array-like object).
Rest parameters were designed to replace arguments in ECMAScript.
ES5
ES6 way (rest parameters and spread operator together)
There are two restrictions on rest parameters.
1. There can be only one rest parameter, and the rest parameter must be last.
2. Rest parameters cannot be used in an object literal setter.
Object literal setters are restricted to a single argument and rest parameters have, by definition, an infinite number of arguments.