Modern JavaScript Cheatsheet
Cheatsheet for the JavaScript knowledge you will frequently encounter in mo...
README
Modern JavaScript Cheatsheet
If you like this content, you can ping me or follow me on Twitter :+1:
Introduction
Motivation
Note: Most of the concepts introduced here are coming from a JavaScript language update (ES2015, often called ES6). You can find new features added by this update here; it's very well done.
Complementary Resources
Table of Contents
Notions
Variable declaration: var, const, let
Short explanation
Scope | Reassignable | Mutable | Temporal Dead Zone | |
---|---|---|---|---|
const | Block | No | Yes | Yes |
let | Block | Yes | Yes | Yes |
var | Function | Yes | Yes | No |
Sample code
- ``` js
- const person = "Nick";
- person = "John" // Will raise an error, person can't be reassigned
- ```
- ``` js
- let person = "Nick";
- person = "John";
- console.log(person) // "John", reassignment is allowed with let
- ```
Detailed explanation
var
- ``` js
- function myFunction() {
- var myVar = "Nick";
- console.log(myVar); // "Nick" - myVar is accessible inside the function
- }
- console.log(myVar); // Throws a ReferenceError, myVar is not accessible outside the function.
- ```
- ``` js
- function myFunction() {
- var myVar = "Nick";
- if (true) {
- var myVar = "John";
- console.log(myVar); // "John"
- // actually, myVar being function scoped, we just erased the previous myVar value "Nick" for "John"
- }
- console.log(myVar); // "John" - see how the instructions in the if block affected this value
- }
- console.log(myVar); // Throws a ReferenceError, myVar is not accessible outside the function.
- ```
- ``` js
- console.log(myVar) // undefined -- no error raised
- var myVar = 2;
- ```
- ``` js
- var myVar;
- console.log(myVar) // undefined -- no error raised
- myVar = 2;
- ```
let
- ``` js
- function myFunction() {
- let myVar = "Nick";
- if (true) {
- let myVar = "John";
- console.log(myVar); // "John"
- // actually, myVar being block scoped, we just created a new variable myVar.
- // this variable is not accessible outside this block and totally independent
- // from the first myVar created !
- }
- console.log(myVar); // "Nick", see how the instructions in the if block DID NOT affect this value
- }
- console.log(myVar); // Throws a ReferenceError, myVar is not accessible outside the function.
- ```
- ``` js
- console.log(myVar) // raises a ReferenceError !
- let myVar = 2;
- ```
Note: Technically, let and const variables declarations are being hoisted too, but not their assignation. Since they're made so that they can't be used before assignation, it intuitively feels like there is no hoisting, but there is. Find out more on this very detailed explanation here if you want to know more.
- ``` js
- let myVar = 2;
- let myVar = 3; // Raises a SyntaxError
- ```
const
- ``` js
- const myVar = "Nick";
- myVar = "John" // raises an error, reassignment is not allowed
- ```
- ``` js
- const myVar = "Nick";
- const myVar = "John" // raises an error, re-declaration is not allowed
- ```
- ``` js
- const person = {
- name: 'Nick'
- };
- person.name = 'John' // this will work ! person variable is not completely reassigned, but mutated
- console.log(person.name) // "John"
- person = "Sandra" // raises an error, because reassignment is not allowed with const declared variables
- ```
- ``` js
- const person = [];
- person.push('John'); // this will work ! person variable is not completely reassigned, but mutated
- console.log(person[0]) // "John"
- person = ["Nick"] // raises an error, because reassignment is not allowed with const declared variables
- ```
External resource
Sample code
- ``` js
- function double(x) { return x * 2; } // Traditional way
- console.log(double(2)) // 4
- ```
- ``` js
- const double = x => x * 2; // Same function written as an arrow function with implicit return
- console.log(double(2)) // 4
- ```
- ``` js
- function myFunc() {
- this.myVar = 0;
- setTimeout(() => {
- this.myVar++;
- console.log(this.myVar) // 1
- }, 0);
- }
- ```
Detailed explanation
Concision
- ``` js
- function double(x) {
- return x * 2; // this function explicitly returns x * 2, *return* keyword is used
- }
- ```
- ``` js
- const double = (x) => {
- return x * 2; // Explicit return here
- }
- ```
- ``` js
- const double = (x) => x * 2; // Correct, returns x*2
- ```
Note: If your function does not return a value (with side effects), it doesn't do an explicit nor an implicit return.
- ``` js
- const getPerson = () => ({ name: "Nick", age: 24 })
- console.log(getPerson()) // { name: "Nick", age: 24 } -- object implicitly returned by arrow function
- ```
- ``` js
- const double = (x) => x * 2; // this arrow function only takes one parameter
- ```
- ``` js
- const double = x => x * 2; // this arrow function only takes one parameter
- ```
- ``` js
- () => { // parentheses are provided, everything is fine
- const x = 2;
- return x;
- }
- ```
- ``` js
- => { // No parentheses, this won't work!
- const x = 2;
- return x;
- }
- ```
this reference
- ``` js
- function myFunc() {
- this.myVar = 0;
- var that = this; // that = this trick
- setTimeout(
- function() { // A new *this* is created in this function scope
- that.myVar++;
- console.log(that.myVar) // 1
- console.log(this.myVar) // undefined -- see function declaration above
- },
- 0
- );
- }
- ```
- ``` js
- function myFunc() {
- this.myVar = 0;
- setTimeout(
- () => { // this taken from surrounding, meaning myFunc here
- this.myVar++;
- console.log(this.myVar) // 1
- },
- 0
- );
- }
- ```
Useful resources
Function default parameter value
- ``` js
- function myFunc(x = 10) {
- return x;
- }
- console.log(myFunc()) // 10 -- no value is provided so x default value 10 is assigned to x in myFunc
- console.log(myFunc(5)) // 5 -- a value is provided so x is equal to 5 in myFunc
- console.log(myFunc(undefined)) // 10 -- undefined value is provided so default value is assigned to x
- console.log(myFunc(null)) // null -- a value (null) is provided, see below for more details
- ```
Note: Default value assignment can be used with destructured parameters as well (see next notion to see an example)
External resource
Destructuring objects and arrays
Explanation with sample code
- ``` js
- const person = {
- firstName: "Nick",
- lastName: "Anderson",
- age: 35,
- sex: "M"
- }
- ```
- ``` js
- const first = person.firstName;
- const age = person.age;
- const city = person.city || "Paris";
- ```
- ``` js
- const { firstName: first, age, city = "Paris" } = person; // That's it !
- console.log(age) // 35 -- A new variable age is created and is equal to person.age
- console.log(first) // "Nick" -- A new variable first is created and is equal to person.firstName
- console.log(firstName) // ReferenceError -- person.firstName exists BUT the new variable created is named first
- console.log(city) // "Paris" -- A new variable city is created and since person.city is undefined, city is equal to the default value provided "Paris".
- ```
- ``` js
- function joinFirstLastName(person) {
- const firstName = person.firstName;
- const lastName = person.lastName;
- return firstName + '-' + lastName;
- }
- joinFirstLastName(person); // "Nick-Anderson"
- ```
- ``` js
- function joinFirstLastName({ firstName, lastName }) { // we create firstName and lastName variables by destructuring person parameter
- return firstName + '-' + lastName;
- }
- joinFirstLastName(person); // "Nick-Anderson"
- ```
- ``` js
- const joinFirstLastName = ({ firstName, lastName }) => firstName + '-' + lastName;
- joinFirstLastName(person); // "Nick-Anderson"
- ```
- ``` js
- const myArray = ["a", "b", "c"];
- ```
- ``` js
- const x = myArray[0];
- const y = myArray[1];
- ```
- ``` js
- const [x, y] = myArray; // That's it !
- console.log(x) // "a"
- console.log(y) // "b"
- ```
Useful resources
Array methods - map / filter / reduce / find
Sample code
- ``` js
- const numbers = [0, 1, 2, 3, 4, 5, 6];
- const doubledNumbers = numbers.map(n => n * 2); // [0, 2, 4, 6, 8, 10, 12]
- const evenNumbers = numbers.filter(n => n % 2 === 0); // [0, 2, 4, 6]
- const sum = numbers.reduce((prev, next) => prev + next, 0); // 21
- const greaterThanFour = numbers.find((n) => n>4); // 5
- ```
- ``` js
- const students = [
- { name: "Nick", grade: 10 },
- { name: "John", grade: 15 },
- { name: "Julia", grade: 19 },
- { name: "Nathalie", grade: 9 },
- ];
- const aboveTenSum = students
- .map(student => student.grade) // we map the students array to an array of their grades
- .filter(grade => grade >= 10) // we filter the grades array to keep those 10 or above
- .reduce((prev, next) => prev + next, 0); // we sum all the grades 10 or above one by one
- console.log(aboveTenSum) // 44 -- 10 (Nick) + 15 (John) + 19 (Julia), Nathalie below 10 is ignored
- ```
Explanation
- ``` js
- const numbers = [0, 1, 2, 3, 4, 5, 6];
- ```
Array.prototype.map()
- ``` js
- const doubledNumbers = numbers.map(function(n) {
- return n * 2;
- });
- console.log(doubledNumbers); // [0, 2, 4, 6, 8, 10, 12]
- ```
- ``` js
- const doubleN = function(n) { return n * 2; };
- const doubledNumbers = numbers.map(doubleN);
- console.log(doubledNumbers); // [0, 2, 4, 6, 8, 10, 12]
- ```
- ``` js
- const doubledNumbers = numbers.map(n => n * 2);
- console.log(doubledNumbers); // [0, 2, 4, 6, 8, 10, 12]
- ```
Note: If you do not need to return a new array and just want to do a loop that has side effects, you might just want to use a for / forEach loop instead of a map.
Array.prototype.filter()
- ``` js
- const evenNumbers = numbers.filter(function(n) {
- return n % 2 === 0; // true if "n" is par, false if "n" isn't
- });
- console.log(evenNumbers); // [0, 2, 4, 6]
- ```
- ``` js
- const evenNumbers = numbers.filter(n => n % 2 === 0);
- console.log(evenNumbers); // [0, 2, 4, 6]
- ```
Array.prototype.reduce()
- ``` js
- const sum = numbers.reduce(
- function(acc, n) {
- return acc + n;
- },
- 0 // accumulator variable value at first iteration step
- );
- console.log(sum) // 21
- ```
- ``` js
- const sum = numbers.reduce((acc, n) => acc + n, 0);
- console.log(sum) // 21
- ```
At first iteration step
At second iteration step
At third iteration step
At fourth iteration step
[...] At last iteration step
Array.prototype.find()
- ``` js
- const greaterThanZero = numbers.find(function(n) {
- return n > 0; // return number just greater than 0 is present
- });
- console.log(greaterThanZero); // 1
- ```
External Resource
Spread operator "..."
Sample code
- ``` js
- const arr1 = ["a", "b", "c"];
- const arr2 = [...arr1, "d", "e", "f"]; // ["a", "b", "c", "d", "e", "f"]
- ```
- ``` js
- function myFunc(x, y, ...params) {
- console.log(x);
- console.log(y);
- console.log(params)
- }
- myFunc("a", "b", "c", "d", "e", "f")
- // "a"
- // "b"
- // ["c", "d", "e", "f"]
- ```
- ``` js
- const { 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 }
- const n = { x, y, ...z };
- console.log(n); // { x: 1, y: 2, a: 3, b: 4 }
- ```
Explanation
In iterables (like arrays)
- ``` js
- const arr1 = ["a", "b", "c"];
- const arr2 = [arr1, "d", "e", "f"]; // [["a", "b", "c"], "d", "e", "f"]
- ```
- ``` js
- const arr1 = ["a", "b", "c"];
- const arr2 = [...arr1, "d", "e", "f"]; // ["a", "b", "c", "d", "e", "f"]
- ```
Function rest parameter
- ``` js
- function myFunc() {
- for (var i = 0; i < arguments.length; i++) {
- console.log(arguments[i]);
- }
- }
- myFunc("Nick", "Anderson", 10, 12, 6);
- // "Nick"
- // "Anderson"
- // 10
- // 12
- // 6
- ```
- ``` js
- function createStudent(firstName, lastName, ...grades) {
- // firstName = "Nick"
- // lastName = "Anderson"
- // [10, 12, 6] -- "..." takes all other parameters passed and creates a "grades" array variable that contains them
- const avgGrade = grades.reduce((acc, curr) => acc + curr, 0) / grades.length; // computes average grade from grades
- return {
- firstName: firstName,
- lastName: lastName,
- grades: grades,
- avgGrade: avgGrade
- }
- }
- const student = createStudent("Nick", "Anderson", 10, 12, 6);
- console.log(student);
- // {
- // firstName: "Nick",
- // lastName: "Anderson",
- // grades: [10, 12, 6],
- // avgGrade: 9,33
- // }
- ```
Note: createStudent function is bad because we don't check if grades.length exists or is different from 0. But it's easier to read this way, so I didn't handle this case.
Object properties spreading
- ``` js
- const myObj = { x: 1, y: 2, a: 3, b: 4 };
- const { x, y, ...z } = myObj; // object destructuring here
- console.log(x); // 1
- console.log(y); // 2
- console.log(z); // { a: 3, b: 4 }
- // z is the rest of the object destructured: myObj object minus x and y properties destructured
- const n = { x, y, ...z };
- console.log(n); // { x: 1, y: 2, a: 3, b: 4 }
- // Here z object properties are spread into n
- ```
External resources
Object property shorthand
- ``` js
- const x = 10;
- const myObj = { x };
- console.log(myObj.x) // 10
- ```
Explanation
- ``` js
- const x = 10;
- const y = 20;
- const myObj = {
- x: x, // assigning x variable value to myObj.x
- y: y // assigning y variable value to myObj.y
- };
- console.log(myObj.x) // 10
- console.log(myObj.y) // 20
- ```
- ``` js
- const x = 10;
- const y = 20;
- const myObj = {
- x,
- y
- };
- console.log(myObj.x) // 10
- console.log(myObj.y) // 20
- ```
External resources
Promises
Sample code
- ``` js
- const fetchingPosts = new Promise((res, rej) => {
- $.get("/posts")
- .done(posts => res(posts))
- .fail(err => rej(err));
- });
- fetchingPosts
- .then(posts => console.log(posts))
- .catch(err => console.log(err));
- ```
Explanation
Create the promise
- ``` js
- const xFetcherPromise = new Promise( // Create promise using "new" keyword and store it into a variable
- function(resolve, reject) { // Promise constructor takes a function parameter which has resolve and reject parameters itself
- $.get("X") // Launch the Ajax request
- .done(function(X) { // Once the request is done...
- resolve(X); // ... resolve the promise with the X value as parameter
- })
- .fail(function(error) { // If the request has failed...
- reject(error); // ... reject the promise with the error as parameter
- });
- }
- )
- ```
Promise handlers usage
- ``` js
- xFetcherPromise
- .then(function(X) {
- console.log(X);
- })
- .catch(function(err) {
- console.log(err)
- })
- ```
Note : If the promise has already been fulfilled or rejected when a corresponding handler is attached, the handler will be called, so there is no race condition between an asynchronous operation completing and its handlers being attached. (Ref: MDN)
External Resources
Template literals
Sample code
- ``` js
- const name = "Nick";
- `Hello ${name}, the following expression is equal to four : ${2+2}`;
- // Hello Nick, the following expression is equal to four: 4
- ```
External resources
Tagged template literals
Note : A famous library named styled-components heavily relies on this feature.
- ``` js
- function highlight(strings, ...values) {
- const interpolation = strings.reduce((prev, current) => {
- return prev + current + (values.length ? "<mark>" + values.shift() + "</mark>" : "");
- }, "");
- return interpolation;
- }
- const condiment = "jam";
- const meal = "toast";
- highlight`I like ${condiment} on ${meal}.`;
- // "I like jam on toast."
- ```
- ``` js
- function comma(strings, ...values) {
- return strings.reduce((prev, next) => {
- let value = values.shift() || [];
- value = value.join(", ");
- return prev + next + value;
- }, "");
- }
- const snacks = ['apples', 'bananas', 'cherries'];
- comma`I like ${snacks} to snack on.`;
- // "I like apples, bananas, cherries to snack on."
- ```
External resources
Imports / Exports
Explanation with sample code
Named exports
Note : You can only name-export first-class citizens that have a name.
- ``` js
- // mathConstants.js
- export const pi = 3.14;
- export const exp = 2.7;
- export const alpha = 0.35;
- // -------------
- // myFile.js
- import { pi, exp } from './mathConstants.js'; // Named import -- destructuring-like syntax
- console.log(pi) // 3.14
- console.log(exp) // 2.7
- // -------------
- // mySecondFile.js
- import * as constants from './mathConstants.js'; // Inject all exported values into constants variable
- console.log(constants.pi) // 3.14
- console.log(constants.exp) // 2.7
- ```
- ``` js
- import { foo as bar } from 'myFile.js'; // foo is imported and injected into a new bar variable
- ```
Default import / export
- ``` js
- // coolNumber.js
- const ultimateNumber = 42;
- export default ultimateNumber;
- // ------------
- // myFile.js
- import number from './coolNumber.js';
- // Default export, independently from its name, is automatically injected into number variable;
- console.log(number) // 42
- ```
- ``` js
- // sum.js
- export default function sum(x, y) {
- return x + y;
- }
- // -------------
- // myFile.js
- import sum from './sum.js';
- const result = sum(1, 2);
- console.log(result) // 3
- ```
External resources
- ``` js
- function myFunc() {
- ...
- }
- // After each statement, you find the value of *this* in myFunc
- myFunc.call("myString", "hello") // "myString" -- first .call parameter value is injected into *this*
- // In non-strict-mode
- myFunc("hello") // window -- myFunc() is syntax sugar for myFunc.call(window, "hello")
- // In strict-mode
- myFunc("hello") // undefined -- myFunc() is syntax sugar for myFunc.call(undefined, "hello")
- ```
- ``` js
- var person = {
- myFunc: function() { ... }
- }
- person.myFunc.call(person, "test") // person Object -- first call parameter is injected into *this*
- person.myFunc("test") // person Object -- person.myFunc() is syntax sugar for person.myFunc.call(person, "test")
- var myBoundFunc = person.myFunc.bind("hello") // Creates a new function in which we inject "hello" in *this* value
- person.myFunc("test") // person Object -- The bind method has no effect on the original method
- myBoundFunc("test") // "hello" -- myBoundFunc is person.myFunc with "hello" bound to *this*
- ```
External resources
Class
Samples
- ``` js
- var Person = function(name, age) {
- this.name = name;
- this.age = age;
- }
- Person.prototype.stringSentence = function() {
- return "Hello, my name is " + this.name + " and I'm " + this.age;
- }
- ```
- ``` js
- class Person {
- constructor(name, age) {
- this.name = name;
- this.age = age;
- }
- stringSentence() {
- return `Hello, my name is ${this.name} and I am ${this.age}`;
- }
- }
- const myPerson = new Person("Manu", 23);
- console.log(myPerson.age) // 23
- console.log(myPerson.stringSentence()) // "Hello, my name is Manu and I'm 23
- ```
External resources
Extends and super keywords
Sample Code
- ``` js
- class Polygon {
- constructor(height, width) {
- this.name = 'Polygon';
- this.height = height;
- this.width = width;
- }
- getHelloPhrase() {
- return `Hi, I am a ${this.name}`;
- }
- }
- class Square extends Polygon {
- constructor(length) {
- // Here, it calls the parent class' constructor with lengths
- // provided for the Polygon's width and height
- super(length, length);
- // Note: In derived classes, super() must be called before you
- // can use 'this'. Leaving this out will cause a reference error.
- this.name = 'Square';
- this.length = length;
- }
- getCustomHelloPhrase() {
- const polygonPhrase = super.getHelloPhrase(); // accessing parent method with super.X() syntax
- return `${polygonPhrase} with a length of ${this.length}`;
- }
- get area() {
- return this.height * this.width;
- }
- }
- const mySquare = new Square(10);
- console.log(mySquare.area) // 100
- console.log(mySquare.getHelloPhrase()) // 'Hi, I am a Square' -- Square inherits from Polygon and has access to its methods
- console.log(mySquare.getCustomHelloPhrase()) // 'Hi, I am a Square with a length of 10'
- ```
- ``` js
- class Square extends Polygon {
- constructor(length) {
- this.height; // ReferenceError, super needs to be called first!
- // Here, it calls the parent class' constructor with lengths
- // provided for the Polygon's width and height
- super(length, length);
- // Note: In derived classes, super() must be called before you
- // can use 'this'. Leaving this out will cause a reference error.
- this.name = 'Square';
- }
- }
- ```
External Resources
Async Await
Note : You must understand what promises are and how they work before trying to understand async / await since they rely on it.
Note 2: [await must be used in an async function](https://hackernoon.com/6-reasons-why-javascripts-async-await-blows-promises-away-tutorial-c7ec10518dd9#f3f0), which means that you can't use await in the top level of our code since that is not inside an async function.
Sample code
- ``` js
- async function getGithubUser(username) { // async keyword allows usage of await in the function and means function returns a promise
- const response = await fetch(`https://api.github.com/users/${username}`); // Execution is paused here until the Promise returned by fetch is resolved
- return response.json();
- }
- getGithubUser('mbeaudru')
- .then(user => console.log(user)) // logging user response - cannot use await syntax since this code isn't in async function
- .catch(err => console.log(err)); // if an error is thrown in our async function, we will catch it here
- ```
Explanation with sample code
- ``` js
- async function myFunc() {
- // we can use await operator because this function is async
- return "hello world";
- }
- myFunc().then(msg => console.log(msg)) // "hello world" -- myFunc's return value is turned into a promise because of async operator
- ```
Note : fetch is a function that returns a Promise that allows to do an AJAX request
- ``` js
- function getGithubUser(username) {
- return fetch(`https://api.github.com/users/${username}`).then(response => response.json());
- }
- getGithubUser('mbeaudru')
- .then(user => console.log(user))
- .catch(err => console.log(err));
- ```
- ``` js
- async function getGithubUser(username) { // promise + await keyword usage allowed
- const response = await fetch(`https://api.github.com/users/${username}`); // Execution stops here until fetch promise is fulfilled
- return response.json();
- }
- getGithubUser('mbeaudru')
- .then(user => console.log(user))
- .catch(err => console.log(err));
- ```
Note : await expressions needs to be wrapped in parentheses to call its resolved value's methods and properties on the same line.
- ``` js
- async function fetchPostById(postId) {
- const token = (await fetch('token_url')).json().token;
- const post = (await fetch(`/posts/${postId}?token=${token}`)).json();
- const author = (await fetch(`/users/${post.authorId}`)).json();
- post.author = author;
- return post;
- }
- fetchPostById('gzIrzeo64')
- .then(post => console.log(post))
- .catch(err => console.log(err));
- ```
Error handling
Note : Promises behave the same!
- ``` js
- function getUser() { // This promise will be rejected!
- return new Promise((res, rej) => rej("User not found !"));
- }
- function getAvatarByUsername(userId) {
- return getUser(userId).then(user => user.avatar);
- }
- function getUserAvatar(username) {
- return getAvatarByUsername(username).then(avatar => ({ username, avatar }));
- }
- getUserAvatar('mbeaudru')
- .then(res => console.log(res))
- .catch(err => console.log(err)); // "User not found !"
- ```
- ``` js
- async function getUser() { // The returned promise will be rejected!
- throw "User not found !";
- }
- async function getAvatarByUsername(userId) => {
- const user = await getUser(userId);
- return user.avatar;
- }
- async function getUserAvatar(username) {
- var avatar = await getAvatarByUsername(username);
- return { username, avatar };
- }
- getUserAvatar('mbeaudru')
- .then(res => console.log(res))
- .catch(err => console.log(err)); // "User not found !"
- ```
External resources
Truthy / Falsy
- ``` js
- if (myVar) {}
- ```
- ``` js
- !0 // true -- 0 is falsy so it returns true
- !!0 // false -- 0 is falsy so !0 returns true so !(!0) returns false
- !!"" // false -- empty string is falsy so NOT (NOT false) equals false
- ```
- ``` js
- new Boolean(0) // false
- new Boolean(1) // true
- ```
- ``` js
- myVar ? "truthy" : "falsy"
- ```
- ``` js
- let a = [] == true // a is false since [].toString() give "" back.
- let b = [1] == true // b is true since [1].toString() give "1" back.
- let c = [2] == true // c is false since [2].toString() give "2" back.
- ```
External resources
Anamorphisms and Catamorphisms
Anamorphisms
- ``` js
- function downToOne(n) {
- const list = [];
- for (let i = n; i > 0; --i) {
- list.push(i);
- }
- return list;
- }
- downToOne(5)
- //=> [ 5, 4, 3, 2, 1 ]
- ```