Andrei Antal
Contents
To be continued...
function getColor(condition) {
if (condition) {
var value = "blue";
// other code
return value;
} else {
return null;
}
}ES5 variable hoisting
function getColor(condition) {
var value; // undefined
if (condition) {
value = "blue";
// other code
return value;
} else {
return null;
}
}function getColor(condition) {
if (condition) {
var value = "blue";
// ...
return value;
} else {
// value = undefined
return null;
}
// value = undefined
}ES5 variable hoisting
for (var i = 0; i < 10; i++) {
process(items[i]);
}ES5 variables in loops
var funcs = [];
for (var i = 0; i < 10; i++) {
funcs.push(function() { console.log(i); });
}ES5 functions in loops
console.log(i); // 10funcs.forEach(function(func) {
func(); // 10, 10, 10....
});
The LET declarations
function getColor(condition) {
if (condition) {
let value = "blue";
// other code
return value;
} else {
// value doesn't exist here - ReferenceError
return null;
}
// value doesn't exist here - ReferenceError
}Redeclarations
var count = 30;
// Syntax error
let count = 40;var count = 30;
// Does not throw an error
if (condition) {
let count = 40; // shadows the outer variable inside this scope
// more code
}The CONST declarations
// Valid constant
const maxItems = 30;
// Syntax error: missing initialization
const name;var message = "Hello!";
let age = 25;
// Each of these would throw an error.
const message = "Goodbye!";
const age = 30;const maxItems = 5;
maxItems = 6; // throws errorThe CONST declarations
const person = {
name: "Andrei"
};
// works
person.name = "George";
// throws an error - reinitialization
person = {
name: "George"
};Temporal Dead Zone (TDZ)
if (condition) {
console.log(typeof value); // ReferenceError!
let value = "blue";
}console.log(typeof value); // "undefined"
if (condition) {
let value = "blue";
}Loop behaviour - let
for (let i = 0; i < 10; i++) {
process(items[i]);
}var funcs = [];
for (let i = 0; i < 10; i++) {
funcs.push(function() {
console.log(i);
});
}// i is not accessible here - throws an error
console.log(i);funcs.forEach(function(func) {
func(); // 0, 1, 2, 3,...
})Loop behaviour - const
var funcs = [];
// throws an error after one iteration
for (const i = 0; i < 10; i++) {
funcs.push(function() {
console.log(i);
});
}var funcs = [],
object = {
a: true,
b: true,
c: true
};
// doesn't cause an error
for (const key in object) {
funcs.push(function() {
console.log(key);
});
}New string methods :
New string methods
var msg = "Hello world!";
console.log(msg.startsWith("Hello")); // true
console.log(msg.endsWith("!")); // true
console.log(msg.includes("o")); // true
console.log(msg.startsWith("o")); // false
console.log(msg.endsWith("world!")); // true
console.log(msg.includes("x")); // false
console.log(msg.startsWith("o", 4)); // true
console.log(msg.endsWith("o", 8)); // true
console.log(msg.includes("o", 8)); // false
console.log("x".repeat(3)); // "xxx"
console.log("hello".repeat(2)); // "hellohello"
console.log("abc".repeat(4)); // "abcabcabcabc"Template literals
Template literals
let message = `Hello world!`;
console.log(message); // "Hello world!"
console.log(typeof message); // "string"
console.log(message.length); // 12Multiline strings
// old syntax bug
var message = "Multiline \
string";
console.log(message); // "Multiline string"var message = "Multiline \n\
string";
console.log(message); // "Multiline
// string"var message = [
"Multiline ",
"string"
].join("\n");
let message = "Multiline \n" +
"string";Multiline strings
let message = `Multiline
string`;
console.log(message); // "Multiline
// string"
console.log(message.length); // 31let message = `Multiline
string`;
console.log(message); // "Multiline
// string"
console.log(message.length); // 16Multiline strings
let message = `
<table>
<tr>Jane</tr>
<tr>Bond&</tr>
<tr>Lars</tr>
<tr>Croft</tr>
</table>`;
var message = "<table>" +
"<tr>Jane</tr>" +
"<tr>Bond&</tr>" +
"<tr>Lars</tr>" +
"<tr>Croft</tr>" +
"</table>";
Substitutions
let name = "Andrei",
message = `Hello, ${name}.`;
console.log(message); // "Hello, Andrei."let count = 10,
price = 0.25,
message = `${count} items cost $${(count * price).toFixed(2)}.`;
console.log(message); // "10 items cost $2.50."
Tagged Templates
let message = tag`Hello world`;
function tag(literals, ...substitutions) {
// return a string
}Tagged Templates
let count = 10,
price = 0.25,
message = passthru`${count} items cost $${(count * price).toFixed(2)}.`;literals
substitutions
Tagged Templates
let message = tag`Hello world`;
function tag(literals, ...substitutions) {
// return a string
}Object Literal Syntax Extensions
function createPerson(name, age) {
return {
name: name,
age: age
};
}function createPerson(name, age) {
return {
name,
age
};
}Object Literal Syntax Extensions
var person = {
name: "Nicholas",
sayName: function() {
console.log(this.name);
}
};var person = {
name: "Nicholas",
sayName() {
console.log(this.name);
}
};Object Literal Syntax Extensions
let person = {
// method
getGreeting() {
return "Hello";
}
};
// not a method
function shareGreeting() {
return "Hi!";
}Object Literal Syntax Extensions
let person = {
getGreeting() {
return "Hello";
}
};
// prototype is person
let friend = {
getGreeting() {
return super.getGreeting() + ", hi!";
}
};
Object.setPrototypeOf(friend, person);
console.log(friend.getGreeting()); // "Hello, hi!"Object Literal Syntax Extensions
var person = {},
lastName = "last name";
person["first name"] = "Andrei";
person[lastName] = "Antal";
console.log(person["first name"]); // "Andrei"
console.log(person[lastName]); // "Antal"var person = {
"first name": "Andrei"
};
console.log(person["first name"]); // "Andrei"var suffix = " name";
var person = {};
person["first" + suffix] = "Andrei";Object Literal Syntax Extensions
var lastName = "last name";
var person = {
"first name": "Andrei",
[lastName]: "Antal"
};
console.log(person["first name"]); // "Andrei"
console.log(person["last name"]); // "Antal"
var suffix = " name";
var person = {
["first" + suffix]: "Andrei",
["last" + suffix]: "Antal"
};
console.log(person["first name"]); // "Andrei"
console.log(person["last name"]); // "Antal"New methods
console.log(+0 == -0); // true
console.log(+0 === -0); // true
console.log(Object.is(+0, -0)); // false
console.log(NaN == NaN); // false
console.log(NaN === NaN); // false
console.log(Object.is(NaN, NaN)); // trueconsole.log(5 == 5); // true
console.log(5 == "5"); // true
console.log(5 === 5); // true
console.log(5 === "5"); // false
console.log(Object.is(5, 5)); // true
console.log(Object.is(5, "5")); // falseNew methods
Object.assign(target, ...sources)var o1 = { a: 1 };
var o2 = { b: 2 };
var o3 = { c: 3 };
var obj = Object.assign(o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3 }
console.log(o1); // { a: 1, b: 2, c: 3 }, target object itself is changed.Object.assign()
var o1 = { a: 1, b: 1, c: 1 };
var o2 = { b: 2, c: 2 };
var o3 = { c: 3 };
var obj = Object.assign({}, o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3 }
var obj = { a: 1 };
var copy = Object.assign({}, obj);
console.log(copy); // { a: 1 }Symbols - a new type of primitive in JavaScript used for adding non-string values for property names (they don't have a literal form)
let firstName = Symbol("first name"); // Debugging purposes only
let person = {};
person[firstName] = "Andrei";
console.log("first name" in person); // false
console.log(person[firstName]); // "Andrei"
console.log(firstName); // "Symbol(first name)"let firstName = Symbol();
let person = {};
person[firstName] = "Andrei";
console.log(person[firstName]); // "Andrei"
console.log(typeof firstName); // "symbol"Symbols cannot be coerced into strings or numbers
let uid = Symbol.for("uid"),
desc = String(uid);
console.log(desc); // "Symbol(uid)"let uid = Symbol.for("uid"),
desc = uid + ""; // error!let uid = Symbol.for("uid"),
sum = uid / 1; // error!Sharing Symbols
ES6 provides a global symbol registry
let uid = Symbol.for("uid");
let object = {
[uid]: "12345"
};
console.log(object[uid]); // "12345"
console.log(uid); // "Symbol(uid)"
let uid2 = Symbol.for("uid");
console.log(uid === uid2); // true
console.log(object[uid2]); // "12345"
console.log(uid2); // "Symbol(uid)"Sharing Symbols
let uid = Symbol.for("uid");
console.log(Symbol.keyFor(uid)); // "uid"
let uid2 = Symbol.for("uid");
console.log(Symbol.keyFor(uid2)); // "uid"
let uid3 = Symbol("uid");
console.log(Symbol.keyFor(uid3)); // undefinedWell-known symbols
obj instanceof Array;
Array[Symbol.hasInstance](obj);
obj instanceof Array;
Object.prototype.toString()Arrow function syntax
var reflect = value => value;var reflect = (value) => { return value };
// ES5 equivalent function
var reflect = function(value) {
return value;
};
var reflect = (value) => { return value };Arrow function syntax
var getName = () => "Andrei";
// ES5 equivalent function
var getName = function() {
return "Andrei";
};var sum = (num1, num2) => num1 + num2;
// ES5 equivalent function
var sum = function(num1, num2) {
return num1 + num2;
};Arrow function syntax
var getTempItem = id => ({ id: id, name: "Temp" });
// effectively equivalent to:
var getTempItem = function(id) {
return {
id: id,
name: "Temp"
};
};var comparator = (a, b) => a - b;
console.log(typeof comparator); // "function"
console.log(comparator instanceof Function); // trueBinding to this
var PageHandler = {
id: "123456",
init: function() {
document.addEventListener("click", function(event) {
this.doSomething(event.type);
}, false);
},
doSomething: function(type) {
console.log("Handling " + type + " for " + this.id);
}
};
PageHandler.init();Binding to this
var PageHandler = {
id: "123456",
init: function() {
document.addEventListener("click", (function(event) {
this.doSomething(event.type); // no error
}).bind(this), false);
},
doSomething: function(type) {
console.log("Handling " + type + " for " + this.id);
}
};
PageHandler.init();Binding to this
function UiComponent {
var that = this;
var button = document.getElementById(#myButton);
button.addEventListener(click,
function () {
console.log(CLICK);
that.handleClick();
});
}
UiComponent.prototype.handleClick = function () { ... };Binding to this
var PageHandler = {
id: "123456",
init: function() {
document.addEventListener("click",
event => this.doSomething(event.type), false);
},
doSomething: function(type) {
console.log("Handling " + type + " for " + this.id);
}
};Arrow function in array methods
var arr = [5, 6, 13, 0, 1, 18, 23];var sum = arr.reduce((a, b) => a + b); // 66
var even = arr.filter(v => v % 2 == 0); // [6, 0, 18]
var double = arr.map(v => v * 2); // [10, 12, 26, 0, 2, 36, 46]
var sum = arr.reduce(function (a, b) {
return a + b;
}); // 66
var even = arr.filter(function (v) {
return v % 2 == 0;
} // [6, 0, 18]
var double = arr.map(function (v){
return v * 2;
)} // [10, 12, 26, 0, 2, 36, 46]
ES5 way of making "classes"
function Person(name) {
this.name = name;
}
PersonType.prototype.sayName = function() {
console.log(this.name);
};
let person = new Person("Andrei");
person.sayName(); // outputs "Andrei"
console.log(person instanceof Person); // true
console.log(person instanceof Object); // true
console.log(typeof Person); // "function"Prototypes
ES6 Classes
class PersonClass {
constructor(name) { // same as Person constructor function
this.name = name;
}
sayName() { // same as Person.prototype.sayName
console.log(this.name);
}
}
let person = new PersonClass("Andrei");
person.sayName(); // outputs "Andrei"
console.log(person instanceof PersonClass); // true
console.log(person instanceof Object); // true
console.log(typeof PersonClass); // "function"
console.log(typeof PersonClass.prototype.sayName); // "function"ES5 equivalent of a class
let Person = (function() {
"use strict";
const Person = function(name) {
if (typeof new.target === "undefined") {
throw new Error("Constructor must be called with new.");
}
this.name = name;
}
Object.defineProperty(Person.prototype, "sayName", {
value: function() {
if (typeof new.target !== "undefined") {
throw new Error("Method cannot be called with new.");
}
console.log(this.name);
},
enumerable: false,
writable: true,
configurable: true
});
return Person;
}());
Differences between classes and functions:
Class expressions
let PersonClass = class {
// equivalent of the PersonType constructor
constructor(name) {
this.name = name;
}
// equivalent of PersonType.prototype.sayName
sayName() {
console.log(this.name);
}
};
let person = new PersonClass("Andrei");
person.sayName(); // "Andrei"
console.log(person instanceof PersonClass); // true
console.log(person instanceof Object); // true
console.log(typeof PersonClass); // "function"
console.log(typeof PersonClass.prototype.sayName); // "function"Class expressions
let PersonClass = class PersonClass2 {
// equivalent of the PersonType constructor
constructor(name) {
this.name = name;
}
// equivalent of PersonType.prototype.sayName
sayName() {
console.log(this.name);
}
};
console.log(typeof PersonClass); // "function"
console.log(typeof PersonClass2); // "undefined"Accessor properties
class Person {
constructor(name) {
this.name = name;
}
get name() {
return this.name;
}
set name(value) {
this.name = value;
}
}
var descriptor = Object.getOwnPropertyDescriptor(Person.prototype, "name");
console.log("get" in descriptor); // true
console.log("set" in descriptor); // true
console.log(descriptor.enumerable); // falseAccessor properties
let Person = (function() {
"use strict";
const Person = function(name) {
if (typeof new.target === "undefined") {
throw new Error("Constructor must be called with new.");
}
this.name = name;
}
Object.defineProperty(CustomHTMLElement.prototype, "name", {
enumerable: false,
configurable: true,
get: function() {
return this.name;
},
set: function(value) {
this.name= value;
}
});
return Person;
}());Static methods
function PersonType(name) {
this.name = name;
}
// static method
PersonType.create = function(name) {
return new PersonType(name);
};
// instance method
PersonType.prototype.sayName = function() {
console.log(this.name);
};
var person = PersonType.create("Andrei");Static method
class PersonClass {
constructor(name) { // same as PersonType constructor
this.name = name;
}
sayName() { // same as PersonType.prototype.sayName
console.log(this.name);
}
// equivalent of PersonType.create
static create(name) {
return new PersonClass(name);
}
}
let person = PersonClass.create("Andrei");Inheritance - ES5
function Rectangle(length, width) {
this.length = length;
this.width = width;
}
Rectangle.prototype.getArea = function() {
return this.length * this.width;
};function Square(length) {
Rectangle.call(this, length, length);
}
Square.prototype = Object.create(Rectangle.prototype, {
constructor: {
value:Square,
enumerable: true,
writable: true,
configurable: true
}
});
var square = new Square(3);
console.log(square.getArea()); // 9
console.log(square instanceof Square); // true
console.log(square instanceof Rectangle); // truevar square = new Square(3);
console.log(square.getArea()); // 9
console.log(square instanceof Square); // true
console.log(square instanceof Rectangle); // trueInheritance - Classes
class Rectangle {
constructor(length, width) {
this.length = length;
this.width = width;
}
getArea() {
return this.length * this.width;
}
}class Square extends Rectangle {
constructor(length) {
super(length, length); // same as Rectangle.call(this, length, length)
}
}
var square = new Square(3);
console.log(square.getArea()); // 9
console.log(square instanceof Square); // true
console.log(square instanceof Rectangle); // trueShadowing methods
class Square extends Rectangle {
constructor(length) {
super(length, length);
}
// override and shadow Rectangle.prototype.getArea()
getArea() {
return this.length * this.length;
}
}class Square extends Rectangle {
constructor(length) {
super(length, length);
}
// override, shadow, and call Rectangle.prototype.getArea()
getArea() {
return super.getArea();
}
}Abstract classes
// 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
var y = new Rectangle(3, 4); // no error
console.log(y instanceof Shape); // true
Implementing in ES5
let set = Object.create(null);
set.foo = true;
// checking for existence
if (set.foo) {
...
}let map = Object.create(null);
map.foo = "bar";
// retrieving a value
let value = map.foo;
console.log(value); // "bar"let map = Object.create(null);
map[5] = "foo";
console.log(map["5"]); // "foo"let map = Object.create(null),
key1 = {},
key2 = {foo: "foo"};
map[key1] = "bar";
console.log(map[key2]); // "bar"
console.log(key1.toString()); // [object Object]
console.log(key2.toString()); // [object Object]SETS
let set = new Set();
console.log(set.size); // 0set.add(3);
set.add(5);
set.add("5");
console.log(set.size); // 3let set = new Set(),
key1 = {},
key2 = {};
set.add(key1);
set.add(key2);let set = new Set();
set.add(5);
set.add("5");
set.add(5);console.log(set.size); // 2console.log(set.size); // 2SETS
let set = new Set([1, 2, 3, 4, 5, 5, 4, 3]);
console.log(set.size); // 5let set = new Set([5, "5"]);
set.delete(5);
console.log(set.has(5)); // false
console.log(set.size); // 1
set.clear();
console.log(set.has("5")); // false
console.log(set.size); // 0
let set = new Set();
set.add(5);
set.add("5");
console.log(set.has(5)); // true
console.log(set.has(6)); // falseSETS
let set = new Set(),
key = {};
set.add(key);
console.log(set.size); // 1
// eliminate original reference
key = null;
console.log(set.size); // 1WEAK SETS
let set = new WeakSet(),
key = {};
// add the object to the set
set.add(key);
console.log(set.has(key)); // true
// remove the last strong reference to key, also removes from weak set
key = null;
console.log(set.has(key)); // falseMAPS
let map = new Map();
console.log(set.size); // 0map.set("model", "iPhone");
map.set("number", 7);
console.log(map.get("model")); // "iPhone"
console.log(map.get("number")); // 7let map = new Map(),
key1 = {},
key2 = {};
map.set(key1, 5);
map.set(key2, 42);
console.log(map.get(key1)); // 5
console.log(map.get(key2)); // 42MAPS
let map = new Map();
map.set("name", "Andrei");
map.set("age", 29);
console.log(map.size); // 2
console.log(map.has("name")); // true
console.log(map.get("name")); // "Andrei"
console.log(map.has("age")); // true
console.log(map.get("age")); // 29map.delete("name");
console.log(map.has("name")); // false
console.log(map.get("name")); // undefined
console.log(map.size); // 1
map.clear();
console.log(map.has("name")); // false
console.log(map.get("name")); // undefined
console.log(map.has("age")); // false
console.log(map.get("age")); // undefined
console.log(map.size); // 0MAPS
let map = new Map([["name", "Andrei"], ["age", 29]]);
console.log(map.has("name")); // true
console.log(map.get("name")); // "Andrei"
console.log(map.has("age")); // true
console.log(map.get("age")); // 29
console.log(map.size); // 2WEAK MAPS
let map = new Map([["name", "Andrei"], ["age", 29]]);
console.log(map.has("name")); // true
console.log(map.get("name")); // "Andrei"
console.log(map.has("age")); // true
console.log(map.get("age")); // 29
console.log(map.size); // 2Destructuring - the process of breaking a data structure down into smaller parts
let toDoItem = {
name: "Walk dog",
isDone: false
};
// extract data from the object
let name = toDoItem.name;
let isDone = toDoItem.isDone;Destructuring objects
let toDoItem = {
name: "Walk dog",
isDone: false
};
let { name, isDone } = toDoItem;
console.log(name); // "Walk dog"
console.log(isDone); // false
// syntax error!
let { name, isDone };Default values
let toDoItem = {
name: "Walk dog",
isDone: false
};
let { name, isDone, tag } = toDoItem;
console.log(name); // "Walk dog"
console.log(isDone); // false
console.log(tag); // undefinedlet toDoItem = {
name: "Walk dog",
isDone: false
};
let { name, isDone, tag = "Home" } = toDoItem;
console.log(name); // "Walk dog"
console.log(isDone); // false
console.log(tag); // "Home"Value names
let toDoItem = {
name: "Walk dog",
isDone: false
};
let { name: toDoName, isDone: doneState } = toDoItem;
console.log(toDoName); // "Walk dog"
console.log(doneState); // falselet toDoItem = {
name: "Walk dog"
};
let { name: toDoName, isDone: doneState = false } = toDoItem;
console.log(toDoName); // "Walk dog"
console.log(doneState); // falseMultilevel destructuring
let toDoItem = {
details: {
name: "Walk dog",
dueDate: "11.03.2017"
},
isDone: false
};
// extract toDoItem.details.name
let { details: { name: toDoName } } = toDoItem;
console.log(toDoName) // "Walk dog"Array destructuring - works with position in array rather than name
let colors = [ "red", "green", "blue" ];
let [ firstColor, secondColor ] = colors;
console.log(firstColor); // "red"
console.log(secondColor); // "green"let colors = [ "red", [ "green", "lightgreen" ], "blue" ];
// later
let [ firstColor, [ secondColor ] ] = colors;
console.log(firstColor); // "red"
console.log(secondColor); // "green"Array destructuring
let colors = [ "red", "green", "blue" ];
let [ , , thirdColor ] = colors;
console.log(thirdColor); // "blue"let a = 1,
b = 2;
[ a, b ] = [ b, a ];
console.log(a); // 2
console.log(b); // 1Mixed destructuring
let mixed = {
one: 1,
two: 2,
values: [3, 4, 5]
};
let { one: a, two: b, values: [c, , e] } = mixed;
console.log(a); // 1
console.log(b); // 2
console.log(c); // 3
console.log(e); // 5function con() {
console.log("TEST");
return 10;
}
let [x = con()] = []; // "TEST"
let [x = con()] = [1]; // ""Lazy defaults
Destructured Function Parameters
const animal = {
name: 'Dog',
sound: 'wof'
};
function makeSound(options) {
options.name = options.name || 'animal';
console.log(`The ${options.animal} goes ${options.sound}`)
}
makeSound(animal);const animal = {
name: 'Dog',
sound: 'wof'
};
function makeSound({name = 'animal', sound}) {
console.log(`The ${name} goes ${sound}`)
}
makeSound(animal);Destructured Function Parameters
function setCookie(name, value,
{
secure = false,
path = "/",
domain = "example.com",
expires = new Date(Date.now() + 360000000)
} = {}
) {
// ...
}Unnamed Parameters in ES5
function pick(object) {
let result = Object.create(null);
// start at the second parameter
for (let i = 1, len = arguments.length; i < len; i++) {
result[arguments[i]] = object[arguments[i]];
}
return result;
}
let book = {
title: "Understanding ECMAScript 6",
author: "Nicholas C. Zakas",
year: 2015
};
let bookData = pick(book, "author", "year");
console.log(bookData.author); // "Nicholas C. Zakas"
console.log(bookData.year); // 2015Rest Parameter - is indicated by three dots (...) preceding a named parameter
function pick(object, ...keys) {
let result = Object.create(null);
for (let i = 0, len = keys.length; i < len; i++) {
result[keys[i]] = object[keys[i]];
}
return result;
}Rest Parameter restrictions
function pick(object, ...keys, last) {
let result = Object.create(null);
for (let i = 0, len = keys.length; i < len; i++) {
result[keys[i]] = object[keys[i]];
}
return result;
}let object = {
set name(...value) {
// do something
}
};Rest items
let colors = [ "red", "green", "blue" ];
let [ firstColor, ...restColors ] = colors;
console.log(firstColor); // "red"
console.log(restColors.length); // 2
console.log(restColors[0]); // "green"
console.log(restColors[1]); // "blue"
let colors = [ "red", "green", "blue" ];
let [ ...clonedColors ] = colors;
console.log(clonedColors); //"[red,green,blue]"Rest properties (ES2018)
let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };
console.log(x); // 1
console.log(y); // 2
console.log(z); // { a: 3, b: 4 }Spread operator
function logNumbers(a, b, c) {
console.log(a)
console.log(b)
console.log(c)
}
const array = [1,2,3];
logNumbers(...array); // 1 2 3
var args = [0, 1, 2];
logNumbers.apply(null, args);Spread operator - array
const array = [1,2,3];
console.log([...array, 4, 5]); // [1, 2, 3, 4, 5]let set = new Set([1, 2, 3, 3, 3, 4, 5]),
array = [...set];
console.log(array); // [1,2,3,4,5]
var obj = {'key1': 'value1'};
var array = [...obj]; // TypeError: obj is not iterableSpread operator - array
Array operations
const arr1 = [1,2,3];
const arr2 = [2,3,4];
const arr3 = [...arr1, 8, ...arr2];
console.log(arr3); // [1, 2, 3, 8, 2, 3, 4]const arr1 = [1,2,3];
const arr2 = [...arr1]
console.log(arr1); // [1, 2, 3]
console.log(arr2); // [1, 2, 3]
console.log(arr1 === arr2); // falseSpread properties (ES2018)
const obj1 = {a: 'a', b: 'b'};
const obj2 = {c: 'c', ...obj1};
console.log(obj2); // {a: 'a', b: 'b', c: 'c'}const obj1 = {a: 'a', b: 'b', c: 'c'};
const obj2 = {c: 'd', ...obj1};
console.log(obj2); // {a: 'a', b: 'b', c: 'd'}Modules - ES6 way to solve the "everything is in one scope" problem
Exporting - using the export keyword
export var color = "red";
export let person = { name : "Andrei" };
export const value = 7;
export function sum(num1, num2) {
return num1 + num1;
}export class Rectangle {
constructor(length, width) {
this.length = length;
this.width = width;
}
}Exporting - using the export keyword
// this function is private to the module
function subtract(num1, num2) {
return num1 - num2;
}
function multiply(num1, num2) {
return num1 * num2;
}
export { multiply };Importing - using the import keyword
import { sum } from "./example.js";
console.log(sum(1, 2)); // 3
sum = 1; // errorimport * as example from "./example.js";
console.log(example.sum(1, example.number)); // 8
console.log(example.multiply(1, 2)); // 2import { sum, multiply, number } from "./example.js";
console.log(sum(1, number)); // 8
console.log(multiply(1, 2)); // 2Importing - module gets executed only once
import { sum } from "./example.js";
import { multiply } from "./example.js";
import { number } from "./example.js";
if (flag) {
export flag; // syntax error
}
function tryImport() {
import flag from "./example.js"; // syntax error
}Modifying import bindings
// example.js
export var name = "Andrei";
export function setName(newName) {
name = newName;
}import { name, setName } from "./example.js";
console.log(name); // "Andrei"
setName("Alex");
console.log(name); // "Alex"
name = "Nicholas"; // errorRenaming Exports and Imports
function sum(num1, num2) {
return num1 + num2;
}
export { sum as add };import { add as sum } from "./example.js";
console.log(typeof add); // "undefined"
console.log(sum(1, 2)); // 3Default values
export default function(num1, num2) {
return num1 + num2;
}function sum(num1, num2) {
return num1 + num2;
}
export { sum as default };import sum from "./example.js";
console.log(sum(1, 2)); // 3export let color = "red";
export default function(num1, num2) {
return num1 + num2;
}import sum, { color } from "./example.js";
console.log(sum(1, 2)); // 3
console.log(color); // "red"Importing Without Bindings
// example.js
Array.prototype.pushAll = function(items) {
// items must be an array
if (!Array.isArray(items)) {
throw new TypeError("Argument must be an array.");
}
// use built-in push() and spread operator
return this.push(...items);
};import "./example.js";
let colors = ["red", "green", "blue"];
let items = [];
items.pushAll(colors);Using Modules in Web Browsers
<!-- load a module JavaScript file -->
<script type="module" src="module.js"></script>
<!-- include a module inline -->
<script type="module">
import { sum } from "./example.js";
let result = sum(1, 2);
</script>
The for loop
var colors = ["red", "green", "blue"];
for (var i = 0, len = colors.length; i < len; i++) {
console.log(colors[i]);
}Iterators
function createIterator(items) {
var i = 0;
return {
next: function() {
var done = (i >= items.length);
var value = !done ? items[i++] : undefined;
return {
done: done,
value: value
};
}
};
}
var iterator = createIterator([1, 2, 3]);
console.log(iterator.next()); // "{ value: 1, done: false }"
console.log(iterator.next()); // "{ value: 2, done: false }"
console.log(iterator.next()); // "{ value: 3, done: false }"
console.log(iterator.next()); // "{ value: undefined, done: true }"
// for all further calls
console.log(iterator.next()); // "{ value: undefined, done: true }"Generators - functions that return an iterator
// generator
function *createIterator() {
yield 1;
yield 2;
yield 3;
}
// generators are called like regular functions but return an iterator
let iterator = createIterator();
console.log(iterator.next().value); // 1
console.log(iterator.next().value); // 2
console.log(iterator.next().value); // 3
// for all further calls
console.log(iterator.next().value); // undefinedGenerator Function Expressions
let createIterator = function *(items) {
for (let i = 0; i < items.length; i++) {
yield items[i];
}
};
let iterator = createIterator([1, 2, 3]);var o = {
createIterator: function *(items) {
for (let i = 0; i < items.length; i++) {
yield items[i];
}
}
};
let iterator = o.createIterator([1, 2, 3]);Generator Object Methods
The for-of loop
let values = [1, 2, 3];
for (let num of values) {
console.log(num);
}
// 1
// 2
// 3let divs = document.getElementsByTagName("div"); // NodeList Iterator
for (let div of divs) {
console.log(div.id);
}Accessing the Default Iterator
let values = [1, 2, 3];
let iterator = values[Symbol.iterator]();
console.log(iterator.next()); // "{ value: 1, done: false }"
console.log(iterator.next()); // "{ value: 2, done: false }"
console.log(iterator.next()); // "{ value: 3, done: false }"
console.log(iterator.next()); // "{ value: undefined, done: true }"function isIterable(object) {
return typeof object[Symbol.iterator] === "function";
}
console.log(isIterable([1, 2, 3])); // true
console.log(isIterable("Hello")); // true
console.log(isIterable(new Map())); // true
console.log(isIterable(new Set())); // true
console.log(isIterable(new WeakMap())); // false
console.log(isIterable(new WeakSet())); // falseDetecting if an object is iterable
Creating iterables - make an object iterable by creating a Symbol.iterator property containing a generator
let collection = {
items: [],
*[Symbol.iterator]() {
for (let item of this.items) {
yield item;
}
}
};
collection.items.push(1);
collection.items.push(2);
collection.items.push(3);
for (let x of collection) {
console.log(x);
}
// 1
// 2
// 3Passing Arguments to Iterators
function *createIterator() {
let first = yield 1;
let second = yield first + 2; // 4 + 2
yield second + 3; // 5 + 3
}
let iterator = createIterator();
console.log(iterator.next()); // "{ value: 1, done: false }"
console.log(iterator.next(4)); // "{ value: 6, done: false }"
console.log(iterator.next(5)); // "{ value: 8, done: false }"
console.log(iterator.next()); // "{ value: undefined, done: true }"Throwing Errors in Iterators
function *createIterator() {
let first = yield 1;
let second = yield first + 2; // yield 4 + 2, then throw
yield second + 3; // never is executed
}
let iterator = createIterator();
console.log(iterator.next()); // "{ value: 1, done: false }"
console.log(iterator.next(4)); // "{ value: 6, done: false }"
console.log(iterator.throw(new Error("Boom"))); // error thrown from generator
Generator Return Statements
function *createIterator() {
yield 1;
return;
yield 2;
yield 3;
}
let iterator = createIterator();
console.log(iterator.next()); // "{ value: 1, done: false }"
console.log(iterator.next()); // "{ value: undefined, done: true }"function *createIterator() {
yield 1;
return 42;
}
let iterator = createIterator();
console.log(iterator.next()); // "{ value: 1, done: false }"
console.log(iterator.next()); // "{ value: 42, done: true }"
console.log(iterator.next()); // "{ value: undefined, done: true }"Asynchronous task running
run(function *() {
const url = 'https://jsonplaceholder.typicode.com/';
let response = yield fetch(`${url}posts/1`);
const post = yield response.json();
const userId = post.userId;
response = yield fetch(`${url}users/${userId}`);
const user = yield response.json();
return user.name;
})
.then(name => console.log(name));function run(generator) {
const iterator = generator();
function iterate(iteration) {
if(iteration.done) return iteration.value;
const promise = iteration.value;
return promise.then( p => iterate(iterator.next(p)) );
}
return iterate(iterator.next());
Async await (ES2016)
async function getName() {
const url = 'https://jsonplaceholder.typicode.com/';
let response = await fetch(`${url}posts/-1`);
const post = await response.json();
const userId = post.userId;
response = await fetch(`${url}users/${userId}`);
const user = await response.json();
return user.name;
}
getName()
.then(name => console.log(name))
.catch(error => console.log('error'));