# JavaScript best practices

# coding style

# articles

Table of Contents

  • ECMAscript
  • ES6
  • ES2016
  • ES2017
  • ES2018
  • Coding Style
  • Lexical Structure
  • Variables
  • Types
  • Expressions
  • Prototypal Inheritance
  • Classes
  • Exceptions
  • Semicolons
  • Quotes
  • Template Literals
  • Functions
  • Arrow Functions
  • Closures
  • Arrays
  • Loops
  • Events
  • The Event Loop
  • Asynchronous Programming and Callbacks
  • Promises
  • Async and Await
  • Loops and Scope
  • Timers
  • This
  • Strict Mode
  • Immediately-Invoked Function Expressions (IFFE’s)
  • Math Operators
  • The Math Object
  • ES modules
  • CommonJS
  • Glossary

# perfs

Intensive JavaScript - developer.mozilla.org

By default the browser uses a single thread to run all the JavaScript in your page as well as to perform layout, reflows, and garbage collection. This means that long-running JavaScript functions can block the thread, leading to an unresponsive page and a bad user experience.

You can use the Frame rate and Waterfall tools to see when JavaScript is causing performance problems, and to single out the particular functions that need attention.

In this article we'll take an example site whose long-running JavaScript causes responsiveness problems, and apply two different approaches to fixing them. The first is to split long-running functions into pieces and use requestAnimationFrame to schedule each piece, and the second is to run the whole function in a separate thread using a web worker.

# undefined & null check

# JavasScript strict mode

Strict mode : developer.mozilla.org

Le mode strict apporte quelques changements à la sémantique « normale » de JavaScript :

  • le mode strict élimine quelques erreurs silencieuses de JavaScript en les changeant en erreurs explicites (une exception sera levée)
  • le mode strict corrige les erreurs qui font qu'il est difficile pour les moteurs JavaScript d'effectuer des optimisations (exécution plus rapide)
  • le mode strict interdit les mot-clés susceptibles d'être définis dans les futures versions de ECMAScript

# online tools

# when to avoid if and switch

Avoiding If Statements in Our JavaScript Code - medium.com - John Au-Yeung - 20200504

# ternary operator

const bar = foo ? 'foo' : 'bar';
1

instead of

const bar = ((foo) => {
  if (foo) {
    return 'foo'
  }
  return 'bar'
})(foo);
1
2
3
4
5
6

# short circuit

# with &&

const isOnline = true;
const makeRequest = () => {
  //...
}

isOnline && makeRequest();
1
2
3
4
5
6

instead of

const isOnline = true;
const makeRequest = () => {
  //...
}

if (isOnline) {
  makeRequest();
}
1
2
3
4
5
6
7
8

# with ||

const bar = foo || 'abc';
1

instead of

const bar = ((foo) => {
  if (!foo) {
    return 'abc'
  }
  return foo;
})(foo)
1
2
3
4
5
6

# avoid switch

const descs = {
  'border': 'kind dog',
  'pitbull': 'angry dog',
  'german': 'smart dog',
}

const desc = descs['border'];
1
2
3
4
5
6
7

instead of

const getDescription = (breed) => {
  switch (breed) {
    case 'border':
      return 'kind dog';
    case 'pitbull':
      return 'angry dog';
    case 'german':
      return 'smart dog';
    default:
      return ''
  }
}const desc = getDescription('border');
1
2
3
4
5
6
7
8
9
10
11
12

even with the default value

const desc = descs['foo'] || '';
1

# array iteration

Loop through an array in JavaScript : stackoverflow.com

For-each over an array in JavaScript? : stackoverflow.com

Array.forEach n’est pas toujours la meilleure solution ! - blog.overnetcity.com - 20140829

# array / object / Map / Set

# definitions

# array

Array in MDN

const fruits = ['Apple', 'Banana'];

console.log(fruits.length);
// 2
1
2
3
4

It's an indexed list.

Never use the new constructor (const list = new Array();), always use directly the literal (const list = [];). The constructor is slower and there is a common mistake with it, when an array is instantiated with only one arg you define the array length, and not an array of one element : const list = new Array(2); // the array contains in fact [undefined, undefined], but const list = new Array(1, 2) leads to [1, 2].

Resize automatically. Order preserved ('cause indexed). Any types in it. Values can be duplicated (const list = [1, 2, 2, 2, 'toto'];)

See MDN for details.

# object

Object in MDN

const fruit = { name: 'Apple' };
1

See Object initializer in MDN for details with new keyword or Object.create() function.

The const object = new Object(); is rarely used.

The const object = Object.create(proto); is used to create an object based on a proto prototype. const object = Object.create(null); allows object creation without any prototype.

An object is a key/value dictionnary.

A key must be unique and a string (or a Symbol). Keys are unordered, use Map instead if you need to keep an order.

Values can be of any types.

Can't get the size (numbers of K/V) easily.

# Map

Map in MDN

var myMap = new Map();

var keyString = 'a string',
    keyObj = {},
    keyFunc = function() {};

// setting the values
myMap.set(keyString, "value associated with 'a string'");
myMap.set(keyObj, 'value associated with keyObj');
myMap.set(keyFunc, 'value associated with keyFunc');

myMap.size; // 3

// getting the values
myMap.get(keyString);    // "value associated with 'a string'"
myMap.get(keyObj);       // "value associated with keyObj"
myMap.get(keyFunc);      // "value associated with keyFunc"

myMap.get('a string');   // "value associated with 'a string'"
                         // because keyString === 'a string'
myMap.get({});           // undefined, because keyObj !== {}
myMap.get(function() {}) // undefined, because keyFunc !== function () {}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

Objects and maps compared

A key must be unique and from any type (including function).

Keys are ordered.

There is a size() function to get the K/V number.

Map is iterable.

A Map may perform better in scenarios involving frequent addition and removal of key pairs.

# Set

Set in MDN

const set1 = new Set([1, 2, 3, 4, 5]);

console.log(set1.has(1));
// expected output: true

// ...

// iterate a Set
for (let item of mySet) console.log(item);
1
2
3
4
5
6
7
8
9

Set objects are collections of values. You can iterate through the elements of a set in insertion order. A value in the Set may only occur once; it is unique in the Set's collection.

Set, more familiar as a Math concept, is an abstract data type which contains only distinct elements/objects without the need of being allocated orderly by index.

A Set is fundamentally different with an Array, a Set is a keyed collection where an Array is an indexed collection.

Indexed collections are collections of data which are ordered by an index value

Keyed collections are collections which use keys; these contain elements which are iterable in the order of insertion.

# articles

Array in Indexed collections article - MDN

Maps and Sets in Key collections article - MDN

Map vs Object — What and when? - Maya Shavin - medium.com - 20180201

Set vs Array — What and when? - Maya Shavin - medium.com - 20180124

# async / await

Coder l’asynchrone en JavaScript (Par Matthieu Lux)

Tasks, microtasks, queues and schedules - jakearchibald.com - 20150817

In summary:

  • Tasks execute in order, and the browser may render between them
  • Microtasks execute in order, and are executed:
    • after every callback, as long as no other JavaScript is mid-execution
    • at the end of each task

Commentaire SylvainPV sur dev.com (fil privé) :

Ce qu'il faut retenir, c'est qu'un Promise.resolve n'entraîne pas de "vrai asynchronisme", c'est-à-dire qu'il n'attend pas la prochaine boucle d'événements. On a besoin d'attendre la boucle d'événements pour laisser le navigateur faire le rendu et ne pas avoir de freeze.

JavaScript async/await: The Good Part, Pitfalls and How to Use - hackernoon.com - Charlee Li - 20180607

async/await - javascript.info

TLDR :

The async keyword before a function has two effects:

  1. Makes it always return a promise.
  2. Allows to use await in it.

The await keyword before a promise makes JavaScript wait until that promise settles, and then:

  1. If it’s an error, the exception is generated, same as if throw error were called at that very place.
  2. Otherwise, it returns the result, so we can assign it to a value.

Together they provide a great framework to write asynchronous code that is easy both to read and write.

With async/await we rarely need to write promise.then/catch, but we still shouldn’t forget that they are based on promises, because sometimes (e.g. in the outermost scope) we have to use these methods. Also Promise.all is a nice thing to wait for many tasks simultaneously.

# drawbacks

How to escape async/await hell

TLDR : use successives await when not needed, the program control flow should continue. Use Promise.all when needed.

# design patterns

The Comprehensive Guide to JavaScript Design Patterns - www.toptal.com - Marko Mišura - 201803xx

Learning JavaScript Design Patterns - Volume 1.7.0 - Addy Osmani - 2017

Table of Content

  • Introduction
  • What is a Pattern?
  • "Pattern"-ity Testing, Proto-Patterns & The Rule Of Three
  • The Structure Of A Design Pattern
  • Writing Design Patterns
  • Anti-Patterns
  • Categories Of Design Pattern
  • Summary Table Of Design Pattern Categorization
  • JavaScript Design Patterns
    • Constructor Pattern
    • Module Pattern
    • Revealing Module Pattern
    • Singleton Pattern
    • Observer Pattern
    • Mediator Pattern
    • Prototype Pattern
    • Command Pattern
    • Facade Pattern
    • Factory Pattern
    • Mixin Pattern
    • Decorator Pattern
    • Flyweight Pattern
  • JavaScript MV* Patterns
    • MVC Pattern
    • MVP Pattern
    • MVVM Pattern
  • Modern Modular JavaScript Design Patterns
    • AMD
    • CommonJS
    • ES Harmony
  • Design Patterns In jQuery
    • Composite Pattern
    • Adapter Pattern
    • Facade Pattern
    • Observer Pattern
    • Iterator Pattern
    • Lazy Initialization Pattern
    • Proxy Pattern
    • Builder Pattern
  • jQuery Plugin Design Patterns
  • JavaScript Namespacing Patterns
  • Conclusions
  • References

# class

How to Use Classes and Sleep at Night - Dan Abramov - 20151015

Problem :

  • Classes obscure the prototypal inheritance at the core of JS.
  • Classes encourage inheritance but you should prefer composition.
  • Classes tend to lock you into the first bad design you came up with.

How to use classes and sleep at night :

  • Resist making classes your public API.
  • Don’t inherit more than once.
  • Don’t make super calls from methods.
  • Don’t expect people to use your classes.
  • Learn functional programming

Applied to React :

  • You can use class in your JS if you don’t inherit twice and don’t use super.
  • Prefer to write React components as pure functions when possible.
  • Use ES6 classes for components if you need the state or lifecycle hooks.
  • In this case, you may only extend React.Component directly.
  • Give your feedback to the React team on the functional state proposals.