Giter Site home page Giter Site logo

es6-cheetsheet's Introduction

es6-cheetsheet

ES2015, ES2016, ES2017 and beyond.

Pull requests are welcomed 🙏🏻❤️

TABLE OF CONTENTS

Variable Declarations

ES6 brought let and const with proper lexical scoping. let is the new var. Constants work just like let, but can’t be reassigned. let and const are block scoped. Therefore, referencing block-scoped identifiers before they are defined will produce a ReferenceError.

Example using var:

var variable = 5;

{
  console.log('inside', variable); //5
  var variable = 10;
}

console.log('outside', variable); //10

Observe what happens when we use let:

let variable = 5;

{
  console.log('inside', variable); //ReferenceError
  let variable = 10;
}

console.log('outside', variable); //5

Example using const:

const variable = 5;

variable = variable*2; //TypeError: Attempted to assign to readonly property.

Constants are tricky with array and objects. The reference becomes constant but the value does not.

const variable = [5];

console.log(variable) //[5]

variable = [2]; //TypeError: Attempted to assign to readonly property.

variable[0] = 1;
console.log(variable) //[1]

(back to table of contents)

String Templates

Template Strings use back-ticks `` rather than the single or double quotes we're used to with regular strings. A template string could thus be written as follows:

const greeting = `Yo World!`;

String Substitution:

Substitution allows us to place any valid JavaScript expression inside a Template Literal, the result will be output as part of the same string.

Template Strings can contain placeholders for string substitution using the ${ } syntax:

var name = "Brendan";
console.log(`Yo, ${name}!`); //"Yo, Brendan!"

We can use expression interpolation to embed for some readable inline math:

var a = 10;
var b = 10;
console.log(`${a+b}`); //20

They are also very useful for functions inside expressions:

function fn() { return "inside fn"; }
console.log(`outside, ${fn()}, outside`); // outside, inside fn, outside.

Multiline Strings:

Multiline strings in JavaScript have required hacky workarounds for some time. Template Strings significantly simplify multiline strings. Simply include newlines where they are needed and BOOM.

let text = `In ES5 this is
 not legal.`

Unescaped template strings:

we can now construct strings that have special characters in them without needing to escape them explicitly.

var text = "This string contains \"double quotes\" which are escaped.";
let text = `This string contains "double quotes" which don't need to be escaped anymore.`;

(back to table of contents)

Arrow Functions

Arrows are a function shorthand using the => syntax. Arrow functions allow you to preserve the lexical value of this.

Take the example below where we have a nested function, in which we would like to preserve the context of this from its lexical scope:

function Person(name) {
    this.name = name;
}

Person.prototype.prefixName = function (arr) {
    return arr.map(function (character) {
        return this.name + character; // Cannot read property 'name' of undefined
    });
};

Using Arrow Functions, the lexical value of this isn't shadowed and we can re-write the above as shown:

function Person(name) {
    this.name = name;
}

Person.prototype.prefixName = function (arr) {
    return arr.map(character => this.name + character);
};

If an arrow is inside another function, it shares the "arguments" variable of its parent function. Example:

// Lexical arguments
function square() {
  let example = () => {
    let numbers = [];
    for (let number of arguments) {
      numbers.push(number * number);
    }

    return numbers;
  };

  return example();
}

square(2, 4, 7.5, 8, 11.5, 21); // returns: [4, 16, 56.25, 64, 132.25, 441]

(back to table of contents)

Classes

Prior to ES6, we implemented Classes by creating a constructor function and adding properties by extending the prototype:

function Person(name, age, gender) {
    this.name   = name;
    this.age    = age;
    this.gender = gender;
}

Person.prototype.incrementAge = function () {
    return this.age += 1;
};

And created extended classes by the following:

function Personal(name, age, gender, occupation, hobby) {
    Person.call(this, name, age, gender);
    this.occupation = occupation;
    this.hobby = hobby;
}

Personal.prototype = Object.create(Person.prototype);
Personal.prototype.constructor = Personal;
Personal.prototype.incrementAge = function () {
    Person.prototype.incrementAge.call(this);
    this.age += 20;
    console.log(this.age);
};

ES6 classes are a simple sugar over the prototype-based OO pattern. Classes support prototype-based inheritance, super calls, instance and static methods and constructors:

class Person {
    constructor(name, age, gender) {
        this.name   = name;
        this.age    = age;
        this.gender = gender;
    }

    incrementAge() {
      this.age += 1;
    }
}

And extend them using the extends keyword:

class Personal extends Person {
    constructor(name, age, gender, occupation, hobby) {
        super(name, age, gender);
        this.occupation = occupation;
        this.hobby = hobby;
    }

    incrementAge() {
        super.incrementAge();
        this.age += 20;
        console.log(this.age);
    }
}

(back to table of contents)

Destructuring

Destructuring is a convenient way of extracting multiple values from data stored in (possibly nested) objects and Arrays.

Array

Destructuring assignment allows you to assign the properties of an array using syntax that looks similar to array literals.

Old way:

var first = someArray[0];
var second = someArray[1];
var third = someArray[2];

New way:

let [first, second, third] = someArray;

If you want to declare your variables at the same time, you can add a var, let, or const in front of the assignment.

var [ variable1, variable2, ..., variableN ] = array;
let [ variable1, variable2, ..., variableN ] = array;
const [ variable1, variable2, ..., variableN ] = array;

We can even skip a few variables:

let [,,third] = ["foo", "bar", "baz"];
console.log(third); // "baz"

There's also no need to match the full array:

let array = [1, 2, 3, 4];
let [a, b, c] = array;
console.log(a, b, c)
// -------- 1  2  3

You can capture all trailing items in an array with a “rest” pattern:

const array = [1, 2, 3, 4];
const [head, ...tail] = array;
console.log(head); // 1
console.log(tail); // [2, 3, 4]

Rest parameter must be applied as the last element, otherwise you'll get a SyntaxError.

let array = [1, 2, 3, 4];
let [...head, d] = array;
// Uncaught SyntaxError: Unexpected token...

Object

Old way of destructuring an object:

var person = { first_name: 'Joe', last_name: 'Appleseed' };
var first_name = person.first_name; // 'Joe'
var last_name = person.last_name; // 'Appleseed'

New way of destructuring an object:

let person = { first_name: 'Joe', last_name: 'Appleseed' };
let {first_name, last_name} = person;

console.log(first_name); // 'Joe'
console.log(last_name); // 'Appleseed'

When you destructure on properties that are not defined, you get undefined:

let { missing } = {};
console.log(missing); // undefined

You can also destructure in a for-of loop:

const arr = ['a', 'b'];
for (const [index, element] of arr.entries()) {
    console.log(index, element);
}
// Output:
// 0 a
// 1 b

We can use rest operator on an object as well (ES7):

let object = {
  a: 'A',
  b: 'B',
  c: 'C',
  d: 'D',
}

const { a, b, ...other } = object; // es7
console.log(other); // {c: 'C', d: 'D'}

(back to table of contents)

Spread Operator

The spread syntax is simply three dots: ... It allows an iterable to expand in places where 0+ arguments are expected.

Calling Functions without Apply:

function doStuff (x, y, z) { }
var args = [0, 1, 2];

// Call the function, passing args
doStuff.apply(null, args);

Using spread operator:

doStuff(...args);

Or another example using Math functions:

const arr = [2, 4, 8, 6, 0];
const max = Math.max(...arr);

console.log(max); //8

Combine arrays

let mid = [3, 4];
let arr = [1, 2, ...mid, 5, 6]; //[1, 2, 3, 4, 5, 6]

Copy arrays

let arr = [1,2,3];
let arr2 = [...arr]; // like arr.slice()
arr2.push(4)

(back to table of contents)

Getter and setter functions

ES6 has started supporting getter and setter functions within classes. Using the following example:

class Person {

    constructor(name) {
        this._name = name;
    }

    get name() {
      if(this._name) {
        return this._name.toUpperCase();  
      } else {
        return undefined;
      }  
    }

    set name(newName) {
      if (newName == this._name) {
        console.log('I already have this name.');
      } else if (newName) {
        this._name = newName;
      } else {
        return false;
      }
    }
}

let person = new Person("John Doe");

// uses the get method in the background
if (person.name) {
  console.log(person.name);  // John Doe
}

// uses the setter in the background
person.name = "Jane Doe";
console.log(person.name);  // Jane Doe 

(back to table of contents)

Modules

Prior to ES6, we used libraries such as Browserify to create modules on the client-side, and require in Node.js. With ES6, we can now directly use modules of all types (AMD and CommonJS).

Exporting in CommonJS

module.exports = 1;
module.exports = { foo: 'bar' };
module.exports = ['foo', 'bar'];
module.exports = function bar () {};

Exporting in ES6

Named Exports:

export function multiply (x, y) {
  return x * y;
};

As well as exporting a list of objects:

function add (x, y) {
  return x + y;
};

function multiply (x, y) {
  return x * y;
};

export { add, multiply };

Default export:

In our module, we can have many named exports, but we can also have a default export. It’s because our module could be a large library and with default export we can import then an entire module.

Important to note that there's only one default export per module.

export default function (x, y) {
  return x * y;
};

This time we don’t have to use curly braces for importing and we have a chance to name imported statement as we wish.

import multiply from 'module';
// === OR ===
import whatever from 'module';

A module can have both named exports and a default export:

// module.js
export function add (x, y) {
  return x + y;
};
export default function (x, y) {
  return x * y;
};

// app.js
import multiply, { add } from 'module';

The default export is just a named export with the special name default.

// module.js
export default function (x, y) {
  return x * y;
};

// app.js
import { default } from 'module';

Importing in ES6

import { add } from 'module';

We can even import many statements:

import { add, multiply } from 'module';

Imports may also be aliased:

import { 
  add as addition, 
  multiply as multiplication
} from 'module';

and use wildcard (*) to import all exported statemets:

import * from 'module';

(back to table of contents)

Data Structures

Map

A Map is a data structure allows to associate data to a key.

Before it's intruduction in ES6, people generally used objects as maps, by associating some object or value to a specific key value:

const person = {}
person.name = 'John'
person.age = 18

console.log(person.name) //John
console.log(person.age) //18

Map example:

const person = new Map()

person.set('name', 'John')
person.set('age', 18)

const name = person.get('name')
const age = person.get('age')

console.log(name) //John
console.log(age) //18

The Map also provide us with methods to help us manage the data.

delete() method - deletes an item from a map by key:

person.delete('name')

clear() method - delete all items from a map:

person.clear()

has() method - check if a map contains an item by key:

const hasName = person.has('name')

size() method - check the number of items in a map:

const size = person.size

We can also use a couple of methods to iterate:

entries() — get all entries keys() — get only all keys values() — get only all values

Find more details about Map here

WeakMap

A WeakMap is a special kind of map.

In a Map, items are never garbage collected. A WeakMap instead lets all its items be freely garbage collected. Every key of a WeakMap is an object. When the reference to this object is lost, the value can be garbage collected.

Main differences between WeakMap and Map:

  • you cannot iterate over the keys or values (or key-values) of a WeakMap
  • you cannot clear all items from a WeakMap
  • you cannot check its size

A WeakMap exposes those methods, which are equivalent to the Map ones:

get(k)
set(k, v)
has(k)
delete(k)

The use cases of a WeakMap are less evident than the ones of a Map, and you might never find the need for them, but essentially it can be used to build a memory-sensitive cache that is not going to interfere with garbage collection, or for careful encapsualtion and information hiding.

Find more details about WeakMap here

Set

A Set is a collection for unique values. The values can be primitives or object references.

let set = new Set();
set.add(1);
set.add('1');
set.add({ key: 'value' });
console.log(set); // Set {1, '1', Object {key: 'value'}}

Most importantly is that it does not allow duplicate values, one good use if to remove duplicate values from an array:

[ ...new Set([1, 2, 3, 1, 2, 3]) ] // [1, 2, 3]

Iteration using built-in method forEach and for..of:

//forEach
let set = new Set([1, '1', { key: 'value' }]);
set.forEach(function (value) {
  console.log(value);
  // 1
  // '1'
  // Object {key: 'value'}
});
// for..of
let set = new Set([1, '1', { key: 'value' }]);
for (let value of set) {
  console.log(value);
  // 1
  // '1'
  // Object {key: 'value'}
};

Similar to Map, Set provides us with methods such as has(), delete(), clear().

Find more details about Set here

WeakSet

Like a WeakMap, WeakSet is a Set that doesn’t prevent its values from being garbage-collected. It has simpler API than WeakMap, because has only three methods:

new WeakSet([iterable])
WeakSet.prototype.add(value)    : any
WeakSet.prototype.has(value)    : boolean
WeakSet.prototype.delete(value) : boolean

Important thing to note WeakSet is a collection that can‘t be iterated and whose size cannot be determined.

Find more details about WeakSet here

(back to table of contents)

Helpful string functions

.includes( )

var string = 'string';
var substring = 'str';

console.log(string.indexOf(substring) > -1);

Instead of checking for a return value > -1 to denote string containment, we can simply use .includes() which will return a boolean:

const string = 'string';
const substring = 'str';

console.log(string.includes(substring)); // true

.repeat( )

function repeat(string, count) {
    var strings = [];
    while(strings.length < count) {
        strings.push(string);
    }
    return strings.join('');
}

In ES6, we now have access to a nicer implementation:

// String.repeat(numberOfRepetitions)
'str'.repeat(3); // 'strstrstr'

(back to table of contents)

Helpful array functions

from

const inventory = [
    {name: 'mars', quantity: 2},
    {name: 'snickers', quantity: 3}
];
console.log(Array.from(inventory, item => item.quantity + 2)); // [4, 5]

of

Array.of("Twinkle", "Little", "Star"); // returns ["Twinkle", "Little", "Star"]

find

const inventory = [
    {name: 'mars', quantity: 2},
    {name: 'snickers', quantity: 3}
];
console.log(inventory.find(item => item.name === 'mars')); // {name: 'mars', quantity: 2}

findIndex

const inventory = [
    {name: 'mars', quantity: 2},
    {name: 'snickers', quantity: 3}
];
console.log(inventory.findIndex(item => item.name === 'mars')); // 0

fill method takes up to three arguments value, start and end. The start and end arguments are optional with default values of 0 and the length of the this object.

[1, 2, 3].fill(1); // [1, 1, 1]
[1, 2, 3].fill(4, 1, 2); // [1, 4, 3]

(back to table of contents)

Promises

Promises are one of the most exciting additions to JavaScript ES6. Promises are a pattern that greatly simplifies asynchronous programming by making the code look synchronous and avoid problems associated with callbacks.

Prior to ES6, we used bluebird or Q. Now we have Promises natively.

A Promise is an object that is used as a placeholder for the eventual results of a deferred (and possibly asynchronous) computation.

The resolve and reject are functions themselves and are used to send back values to the promise object.

const myPromise = new Promise((resolve, reject) => {
    if (Math.random() * 100 <= 90) {
        resolve('Hello, Promises!');
    }
    reject(new Error('In 10% of the cases, I fail. Miserably.'));
});

myPromise.then((resolvedValue) => {
    console.log(resolvedValue); //Hello, Promises!
}, (error) => {
    console.log(error); //In 10% of the cases, I fail. Miserably.
});

Chaining Promises:

Promises allow us to turn our horizontal code (callback hell):

func1(function (value1) {
    func2(value1, function (value2) {
        func3(value2, function (value3) {
          // Do something with value 3
        });
    });
});

Into vertical code like so:

func1(value1)
    .then(func2)
    .then(func3, value3 => {
        // Do something with value 3
    });

Parallelize Promises:

We can use Promise.all() to handle an array of asynchronous operations.

let urls = [
  '/api/commits',
  '/api/issues/opened',
  '/api/issues/assigned',
  '/api/issues/completed',
  '/api/issues/comments',
  '/api/pullrequests'
];

let promises = urls.map((url) => {
  return new Promise((resolve, reject) => {
    $.ajax({ url: url })
      .done((data) => {
        resolve(data);
      });
  });
});

Promise.all(promises)
  .then((results) => {
    // Do something with results of all our promises
 });

(back to table of contents)

Generators

A generator is a function which can be exited and later re-entered. Their context (variable bindings) will be saved across re-entrances.

Generators in JavaScript are a very powerful tool for asynchronous programming as they mitigate the problems with callbacks, such as Callback Hell and Inversion of Control.

This pattern is what async functions are built on top of.

For creating a generator function, we use function * syntax instead of just function.

Calling a generator function does not execute its body immediately; an iterator object for the function is returned instead. When the iterator's next() method is called, the generator function's body is executed until the first yield expression, which specifies the value to be returned from the iterator or, with yield*, delegates to another generator function.

The next() method returns an object with a value property containing the yielded value and a done property which indicates whether the generator has yielded its last value as a boolean. Calling the next() method with an argument will resume the generator function execution, replacing the yield expression where execution was paused with the argument from next().

Simple example:

function* generator(i) {
  yield i;
  yield i + 10;
}

var gen = generator(10);

console.log(gen.next().value);// expected output: 10
console.log(gen.next().value); // expected output: 20

Example with yield*:

function* anotherGenerator(i) {
  yield i + 1;
  yield i + 2;
  yield i + 3;
}

function* generator(i) {
  yield i;
  yield* anotherGenerator(i);
  yield i + 10;
}

var gen = generator(10);

console.log(gen.next().value); // 10
console.log(gen.next().value); // 11
console.log(gen.next().value); // 12
console.log(gen.next().value); // 13
console.log(gen.next().value); // 20

Infinite Data generator example:

function * naturalNumbers() {
  let num = 1;
  while (true) {
    yield num;
    num = num + 1
  }
}
const numbers = naturalNumbers();
console.log(numbers.next().value)
console.log(numbers.next().value)
// 1
// 2

(back to table of contents)

Async Await

  • Async/Await is a new way to write asynchronous code. Previous options for asynchronous code are callbacks and promises.

  • Async/await is built on top of promises. It cannot be used with plain callbacks or node callbacks.

  • Async/await makes asynchronous code look and behave a little more like synchronous code.

Note that await may only be used in functions marked with the async keyword. It works similarly to generators, suspending execution in your context until the promise settles. If the awaited expression isn’t a promise, its casted into a promise.

async await allows us to perform the same thing we accomplished using Generators and Promises with less effort:

var request = require('request');

function getJSON(url) {
  return new Promise(function(resolve, reject) {
    request(url, function(error, response, body) {
      resolve(body);
    });
  });
}

async function main() {
  var data = await getJSON();
  console.log(data);
}

main();

Under the hood, it performs similarly to Generators.

(back to table of contents)

es6-cheetsheet's People

Contributors

mihaiserban avatar

Watchers

James Cloos avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.