2020-07-21 09:37:15 +02:00
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE - RUN doctoc TO UPDATE -->
2020-07-22 18:11:56 +02:00
2020-07-21 09:37:15 +02:00
## Table of Contents
2020-07-21 11:59:24 +02:00
- [Modern JavaScript ](#modern-javascript )
2020-07-21 09:37:15 +02:00
- [Quirks ](#quirks )
2020-07-21 12:34:19 +02:00
- [Undefined everywhere! ](#undefined-everywhere )
2020-07-21 09:37:15 +02:00
- [Printing and interacting with the console ](#printing-and-interacting-with-the-console )
- [Comparing scalar, arrays, and objects ](#comparing-scalar-arrays-and-objects )
- [Always use triple comparators (`===`) instead of double (`==`) ](#always-use-triple-comparators--instead-of-double- )
- [Comparing non-scalar ](#comparing-non-scalar )
- [`Object` methods ](#object-methods )
- [`Object.assign`, spread operator ](#objectassign-spread-operator )
- [`Array` methods ](#array-methods )
- [`Array.includes` (ES7) ](#arrayincludes-es7 )
- [Object literals, assignment and destructuring ](#object-literals-assignment-and-destructuring )
- [Objects ](#objects )
- [Array ](#array )
- [`let` and `const` ](#let-and-const )
2020-07-21 12:34:19 +02:00
- [Hoisting ](#hoisting )
2020-07-21 09:37:15 +02:00
- [Arrow functions ](#arrow-functions )
- [How `this` works in arrow functions ](#how-this-works-in-arrow-functions )
- [Best practices ](#best-practices )
- [Classes ](#classes )
- [Prototypal inheritance ](#prototypal-inheritance )
- [Template literals ](#template-literals )
- [Template tags ](#template-tags )
- [Loops ](#loops )
- [`for... of` ](#for-of )
- [Promises ](#promises )
- [Creating a promise ](#creating-a-promise )
- [Consuming a promise ](#consuming-a-promise )
- [Chaining promises ](#chaining-promises )
- [Async functions ](#async-functions )
- [Modules ](#modules )
2020-07-21 12:16:54 +02:00
- [Other features ](#other-features )
- [Optional chaining ](#optional-chaining )
2020-07-21 09:37:15 +02:00
- [References ](#references )
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
2020-07-21 11:59:24 +02:00
# Modern JavaScript
2020-07-20 17:49:56 +02:00
Note: run code quickly with https://codesandbox.io/s/
2020-07-22 18:11:56 +02:00
- JavaScript: https://codesandbox.io/s/front-end-training-014br
2020-07-20 17:49:56 +02:00
## Quirks
2020-07-21 12:34:19 +02:00
### Undefined everywhere!
There are no required arguments in JavaScript:
```javascript
function hello(name) {
return name;
2020-07-21 12:56:39 +02:00
}
2020-07-21 12:34:19 +02:00
2020-07-21 12:56:39 +02:00
// No raise, will log "undefined"
2020-07-21 12:34:19 +02:00
console.log(hello());
// Here's how to compare to undefined
2020-07-21 12:56:39 +02:00
console.assert(typeof undefined === "undefined");
2020-07-21 12:34:19 +02:00
```
2020-07-20 18:12:51 +02:00
### Printing and interacting with the console
```javascript
// Do not leave console.log in your code! There are linters such as eslint that will check for their absence
console.log("hello");
2020-07-22 18:11:56 +02:00
console.assert(true === true);
2020-07-20 18:12:51 +02:00
```
2020-07-20 17:49:56 +02:00
### Comparing scalar, arrays, and objects
#### Always use triple comparators (`===`) instead of double (`==`)
```javascript
// ???
2020-07-22 18:11:56 +02:00
console.assert("1" == 1); // this is true!
2020-07-20 17:49:56 +02:00
// Better
2020-07-21 09:14:24 +02:00
console.assert(!("1" === 1));
console.assert("1" !== 1);
2020-07-20 17:49:56 +02:00
```
#### Comparing non-scalar
Applied on arrays and objects, `==` and `===` will check for object identity, which is almost never what you want.
```javascript
2020-07-21 09:14:24 +02:00
console.assert({ a: 1 } != { a: 1 });
console.assert({ a: 1 } !== { a: 1 });
2020-07-20 17:49:56 +02:00
2020-07-21 09:14:24 +02:00
const obj = { a: 1 };
const obj2 = obj;
2020-07-22 18:11:56 +02:00
// This is true because obj and obj2 refer to the same object ("identity")
2020-07-21 09:14:24 +02:00
console.assert(obj == obj2);
console.assert(obj === obj2);
2020-07-20 17:49:56 +02:00
```
Use a library such as [lodash ](https://lodash.com/ ) to properly compare objects and array
```javascript
2020-07-21 09:14:24 +02:00
import _ from "lodash";
2020-07-20 17:49:56 +02:00
2020-07-21 09:14:24 +02:00
console.assert(_.isEqual({ a: 1 }, { a: 1 }));
console.assert(_.isEqual([1, 2], [1, 2]));
2020-07-20 18:12:51 +02:00
```
### `Object` methods
#### `Object.assign`, spread operator
`Object.assign` (ES 2015)
### `Array` methods
2020-07-20 17:49:56 +02:00
2020-07-20 18:12:51 +02:00
#### `Array.includes` (ES7)
2020-07-20 17:49:56 +02:00
2020-07-20 18:12:51 +02:00
## Object literals, assignment and destructuring
2020-07-20 17:49:56 +02:00
### Objects
```javascript
2020-07-21 09:14:24 +02:00
const toaster = { size: 2, color: "red", brand: "NoName" };
2020-07-20 17:49:56 +02:00
2020-07-21 12:56:39 +02:00
// Get ("destructure") one object key
2020-07-21 09:14:24 +02:00
const { size } = toaster;
console.assert(size === 2);
2020-07-20 17:49:56 +02:00
2020-07-21 12:56:39 +02:00
// Note: this also works with functions
function destructuredFunction({ color }) {
return color;
}
console.assert(destructuredFunction({ color: "red" }) === "red");
2020-07-20 17:49:56 +02:00
// Get the rest with ...rest
2020-07-21 09:14:24 +02:00
const { color, brand, ...rest } = toaster;
console.assert(_.isEqual(rest, { size: 2 }));
2020-07-20 18:12:51 +02:00
// Set default
2020-07-21 09:14:24 +02:00
const { size2 = 3 } = toaster;
console.assert(size2 === 3);
2020-07-20 18:12:51 +02:00
// Rename variables
2020-07-21 09:14:24 +02:00
const { size: size3 } = toaster;
console.assert(size3 === 2);
2020-07-21 12:56:39 +02:00
```
Enhanced object literals:
2020-07-20 18:12:51 +02:00
2020-07-21 12:56:39 +02:00
```javascript
2020-07-21 09:14:24 +02:00
const name = "Louis";
const person = { name };
console.assert(_.isEqual(person, { name: "Louis" }));
2020-07-20 18:12:51 +02:00
// Dynamic properties
2020-07-21 09:14:24 +02:00
const person2 = { ["first" + "Name"]: "Olympe" };
console.assert(_.isEqual(person2, { firstName: "Olympe" }));
2020-07-20 18:12:51 +02:00
// Btw, you can include quotes although nobody does this
2020-07-21 09:14:24 +02:00
console.assert(_.isEqual(person2, { firstName: "Olympe" }));
2020-07-21 12:08:28 +02:00
// Short form function
const es5Object = {
say: function () {
console.log("hello");
},
};
2020-07-21 12:08:46 +02:00
es5Object.say();
2020-07-21 12:08:28 +02:00
const es6Object = {
say() {
console.log("hello");
},
};
2020-07-21 12:08:46 +02:00
es6Object.say();
2020-07-21 12:56:39 +02:00
// Prototype and super()
const firstObject = {
a: "a",
hello() {
return "hello";
},
};
const secondObject = {
__proto__ : firstObject,
hello() {
return super.hello() + " from second object";
},
};
console.assert(secondObject.hello() === "hello from second object");
2020-07-20 17:49:56 +02:00
```
### Array
```javascript
const theArray = [1, 2, 3];
const [first, second] = theArray;
const [first1, second2, ...rest] = theArray;
console.assert(first === 1);
console.assert(second === 2);
console.assert(_.isEqualWith(rest, [3]));
```
## `let` and `const`
```javascript
2020-07-21 09:14:24 +02:00
const constantVar = "a";
2020-07-20 17:49:56 +02:00
// Raises "constantVar" is read-only
2020-07-21 09:14:24 +02:00
constantVar = "b";
2020-07-20 17:49:56 +02:00
2020-07-21 12:16:54 +02:00
let theVar = "a";
theVar = "a";
2020-07-20 17:49:56 +02:00
// Note: this will work ok
2020-07-21 09:14:24 +02:00
const constantObject = { a: 1 };
constantObject.a = 2;
constantObject.b = 3;
2020-07-20 17:49:56 +02:00
// Raises: "constantObject" is read-only
2020-07-21 09:14:24 +02:00
constantObject = { a: 1 };
2020-07-20 17:49:56 +02:00
// const and let are block scoped. A block is enclosed in {}
{
2020-07-21 09:14:24 +02:00
const a = "a";
console.log({ a });
2020-07-20 17:49:56 +02:00
}
// Raises: ReferenceError: a is not defined
2020-07-21 09:14:24 +02:00
console.log({ a });
2020-07-20 17:49:56 +02:00
```
Note: try to use `const` as much as you can.
2020-07-22 18:11:56 +02:00
- Those variables can't be reassigned. More constraints leads to safer code.
- You can't define a `const` without providing its initial value.
- Most people do this in modern JS.
2020-07-20 17:49:56 +02:00
Never use `var` :
- `var` variables are initialized with `undefined` , while `let` and `const` vars are not initialized and will raise an error if used before definition.
- `var` is globally or function-scoped, depending on whether it is used inside a function.
- `let` and `const` are block-scoped
- `let` and `const` cannot be reused for the same variable name
2020-07-21 12:34:19 +02:00
### Hoisting
See [Hoisting on MDN ](https://developer.mozilla.org/en-US/docs/Glossary/Hoisting )
2020-07-20 17:49:56 +02:00
## Arrow functions
The first advantage of arrow function is that they're shorter to write:
```javascript
// You can define a function this way:
2020-07-21 09:14:24 +02:00
const myFunction = function () {
2020-07-20 17:49:56 +02:00
console.log("hello world");
2020-07-21 09:14:24 +02:00
};
2020-07-20 17:49:56 +02:00
// With an arrow function, you save a few characters:
const myArrowFunction = () => {
console.log("hello world");
2020-07-21 09:14:24 +02:00
};
2020-07-20 17:49:56 +02:00
// Some things, like params parentheses, and function code brackets, are optional
2020-07-21 09:14:24 +02:00
const myFunctionToBeShortened = function (a) {
2020-07-20 17:49:56 +02:00
return a;
2020-07-21 09:14:24 +02:00
};
2020-07-20 17:49:56 +02:00
// Shorter arrow function
const myFunctionToBeShortenedArrowV1 = (a) => {
return a;
2020-07-21 09:14:24 +02:00
};
2020-07-20 17:49:56 +02:00
// Shortest arrow function
// Remove single param parenthesis, remove function code bracket, remove return
2020-07-21 09:14:24 +02:00
const myFunctionToBeShortenedArrowV2 = (a) => a;
console.assert(myFunctionToBeShortenedArrowV2(1) === 1);
2020-07-20 17:49:56 +02:00
```
2020-07-20 18:12:51 +02:00
### How `this` works in arrow functions
### Best practices
2020-07-20 17:49:56 +02:00
- I usually keep the parameters parenthesis. If you add a parameter, you'll have to add them back.
2020-07-20 18:12:51 +02:00
## Classes
2020-07-21 12:34:19 +02:00
```javascript
class Toaster {
2020-07-21 12:56:39 +02:00
constructor(color) {
this.color = color;
}
2020-07-21 12:34:19 +02:00
2020-07-21 12:56:39 +02:00
dring() {
return "dring";
}
2020-07-21 12:34:19 +02:00
}
// Don't forget new!
// Raises: TypeError: Cannot call a class as a function
// const toaster = Toaster('red');
2020-07-21 12:56:39 +02:00
const toaster = new Toaster("red");
console.log(toaster.dring());
2020-07-21 12:34:19 +02:00
// Inheritance
class BunToaster extends Toaster {
dring() {
2020-07-21 12:56:39 +02:00
return super.dring() + " dring";
2020-07-21 12:34:19 +02:00
}
2020-07-21 12:56:39 +02:00
}
2020-07-21 12:34:19 +02:00
2020-07-21 12:56:39 +02:00
const bunToaster = new BunToaster("red");
console.assert(bunToaster.dring() === "dring dring");
2020-07-21 12:34:19 +02:00
```
Those are my opinions about other class features:
- Avoid using `static` methods, use plain functions instead.
- Avoid using more than one level of inheritance.
- Avoid using getter and setters (`get` and `set` ).
- Avoid using classes altogether.
2020-07-20 18:12:51 +02:00
### Prototypal inheritance
## Template literals
2020-07-21 12:08:28 +02:00
```javascript
const longString = `multi
line
string`;
const name = "Louis";
// Template interpolation
const hello = `Hello ${name}` ;
2020-07-21 12:56:39 +02:00
// You can have expressions
const hello1 = `Hello ${name + "!"}` ;
const hello2 = `Hello ${name === "Louis" ? name : "Noname"}` ;
2020-07-21 12:08:28 +02:00
```
2020-07-20 18:12:51 +02:00
### Template tags
2020-07-21 12:56:39 +02:00
They are used in some libraries, like Apollo and Styled Components.
```javascript
function templateTag(literals, ...expressions) {
console.assert(_.isEqual(literals, ["hello ", ""]));
console.assert(_.isEqual(expressions, [3]));
return _.join(_ .flatten(_.zip(literals, expressions)), "");
}
const result = templateTag`hello ${1 + 2}`;
console.assert(result === "hello 3");
```
2020-07-20 18:12:51 +02:00
## Loops
### `for... of`
Note: prefer using some functional constructs such as `map` , `reduce` , etc.
2020-07-21 12:56:39 +02:00
```javascript
for (const i of [1, 2, 3]) {
console.log({ i });
}
// 1, 2, 3
for (const key in { a: "aaa", b: "bbb" }) {
console.log({ key });
}
// 'a', 'b'
```
2020-07-20 18:12:51 +02:00
## Promises
2020-07-22 09:47:58 +02:00
This is only going to be an introduction to the magnificent world of promise.
- Async functions (seen later) use promises as a building block.
- Promise are indeed async in nature: the calling code continues executing the promise does its thing.
- Some Web API return promises, including `Fetch`
2020-07-20 18:12:51 +02:00
### Creating a promise
2020-07-22 09:47:58 +02:00
Note: we use TypeScript in this example, to clarify what's return. You can ignore the type annotations for now.
```typescript
let isDone: boolean = true
const thePromise = new Promise((resolve, reject) => {
if (isDone) {
resolve("the work is done");
} else {
reject("this is still pending");
}
}
console.assert(thePromise === 'the work is done')
```
TODO
2020-07-20 18:12:51 +02:00
### Consuming a promise
### Chaining promises
## Async functions
## Modules
CommonJS syntax:
2020-07-22 18:11:56 +02:00
```javascript
const lodash = require("lodash");
```
2020-07-20 18:12:51 +02:00
ES Module syntax:
2020-07-22 18:11:56 +02:00
```javascript
import lodash from "lodash";
```
### Imports
```javascript
// Import all and provide under name
import * as toaster from "./toaster";
// Named import (same as object destructuring!)
import { defaultColor, defaultSize } from "./toaster";
// Renaming imports
import { defaultBrand as toasterDefaultBrand } from "./toaster";
// Default import
import createToaster from "./toaster";
// Import both defaults and other
// import createToaster, {defaultColor} from './toaster'
```
### Exports
In `toaster.js` :
```javascript
// Shorthand definition + export
export const defaultSize = 4;
// Alternative export syntax
const defaultBrand = "Moulinex";
export { defaultBrand };
// Default export
const createToaster = ({ size, color }) => ({ size, color });
export default createToaster;
// Note that you have a shorthand default export, but it's not recommended to
// use it as the export won't have a name.
// export default () => ({})
```
2020-07-20 18:12:51 +02:00
2020-07-21 12:16:54 +02:00
## Other features
### Optional chaining
2020-07-20 17:49:56 +02:00
## References
- [ES5 to ESNext — here’ s every feature added to JavaScript since 2015 ](https://www.freecodecamp.org/news/es5-to-esnext-heres-every-feature-added-to-javascript-since-2015-d0c255e13c6e/ )
2020-07-21 12:08:28 +02:00
- [ES2015 / ES6: Basics of modern Javascript ](https://www.slideshare.net/WojciechDzikowski/es2015-es6-basics-of-modern-javascript )