???? TABLE OF CONTENTS

⇨ JS ES5
⇨ JS ES6
⇨ JS Advanced functions
⇨ JS Advanced objects
⇨ Advanced loops
⇨ JS ES7
⇨ JS ES8
⇨ JS ES10
⇨ JS Debugging
⇨ JS Modules
⇨ JS JSON-AJAX
⇨ JS Promises
⇨ JS ES8-ASYNC AWAIT
⇨ JS ES9


Before diving in each topic, take a look at Javascript versions & the browser supports.
If you’re interested to know why and how Javascript is evolving, read this article JavaScript, ES6, ES7, ES10 where are we?

More on compatibility ➡ECMAScript 6 compatibility table


JS ES5 (2009)

ES5 is also known as ECMAScript 5 and ECMAScript 2009. Let’s discover some of the most relevant ES5 Features:

Array Methods

//* Syntax 1
todos.forEach(function(todo, i ){// is equal to todos[i]
    console.log(todo, i); // 'i' is equal to the index i ==> a number
})
//* Syntax 2 : better
function logTodos(todo, i ){
    console.log(todo, i)};
todos.forEach(logTodos);

???? Example:

const basket = ['apples', 'oranges', 'grapes'];
const detailedBasket = {
    apples : 5,
    oranges : 10,
    grapes : 1000
}
// with for loop
for (let i=0; i < basket.length; i++){
    console.log(basket[i]);
}
// with forEach loop
basket.forEach(item => {
    console.log(item);
})

➡Map:

const mapArray = array.map(num => num *2);
console.log('map', mapArray);
//* multiple line
const mapArray = array.map(num => {num *2});

➡Filter

const filterArray = array.filter(num => num > 5);
console.log('filter', filterArray);

➡reduce

const reduceArray = array.reduce((accumulator, num) => {
    return accumulator + num
}, 5);// 5 is the initial accumulator's value.
console.log('reduce', reduceArray);

JS ES6 (2015)

Destructuring:

const obj = {
    player: "baab",
    exp: 100,
    wizardLevel: false
}
//before we had to do:
const player = obj.player;
const exp = obj.exp;
let wizardLevel = obj.wizardLevel;
//* Now we can do:
const {player , exp} = obj;
let {wizardLevel}= obj;

Object Properties:

 //todo: exemple1:
const name = 'john dow';
const obj = {
    [name]: 'hello',
    [1 + 3]: 'hihihi'
}
 //todo: exemple2:
 const a = "simon";
 const b = true;
 const c = {};
 //* before: 
 const obj = {
     a: a,
     b: b,
     c: c
 }
 //* Now if they have the same name
 const obj = {
    a,
    b,
    c
}

Template strings:

//* before:
const greeting = "hello" + name + "it\'sblblblblblb" + something + "!";
//*Now with template strings
const name = "sally";
const age = 30;
const pet = "cat";
const greeting = `hello ${name} you seem to be ${age-10}, what a lovely ${pet} you have`;
//? or even better(we can pass default argument):
function greet(name='', age=30, pet='cat'){
    return `hello ${name} you seem to be ${age-10}, what a lovely ${pet} you have`;
}

type: Symbol:

let sym1 = Symbol();
let sym2 = Symbol('foo');
let sym3 = Symbol('foo');
//* note : sym2 !== sym3 even though they look the same, you make sure there will be never any conflict. most of the times it's used for object properties.
//! Arrow functions:
//* before: 
function add(a,b){
    return a + b;
}
//* Now
const add = (a,b) => a+b;//? for single return
const add = (a,b) => {//? for multiple return
    c = a+b;
    return c;} 

Arrow Functions

const first = () => {
    const greet = 'Hi';
    const second = () => {
        alert(greet);//? closure 'greet'
    }
    return second;
}
const newFunc = first ();
newFunc();

Closures:

  • Rule in javascript
  • child scope always has access to the parent’s scope.
  • ‘closures’ is just saying a function ran, the function executed, it’s never going to execute again. But it’s going to remember that there are references to those variables. So the child scope always has access to the parent scope.

JS Advanced functions

Currying:

const multiply = (a,b) => a * b;
const curriedMultiply = (a) => (b) => a * b;
curriedMultiply(3); // 3 * b;
curriedMultiply(3)(5); // 3 * 5;
const multiplyBy5 = curriedMultiply(5);
multiplyBy5(8); // 8 * 5;

Compose:

const compose = (f,g) => (a) => f(g(a));
const sum = (num) => num + 1;
compose(sum, sum)(5);
// it's like fog(x)= f(g(x)) in mathematique;
//* exemple 2:
const compose = (f, g) => (a) => f(g(a));
const add1 = (num) => num + 1;
const add5 = (num) => num + 5;
compose(add1, add5)(10)

Avoiding Side Effects, functional purity:

var a = 1;
function b(){
    a = 2; // Side Effect, it doing something to change the outside scope.
}
  • make sure that a function always return something we know (a value)(we know exactly what it does)
  • It is really really good practice to be a top-performing developer to have this in mind, of creating functions that minimize side effects and have functional purity. What we call ‘Determinism’, where anything you put into the function it always returns the same thing.
  • What are the two elements of a pure function:
    1. Deterministic –> always produce the same results given the same inputs.
    2. No Side Effects –> It does not depend on any state, or data, change during a program’s execution. It must only depend on its input elements.

JS Advanced objects

Reference type

var object1 = { value: 10};
var object2 = object1;
var object3 = { value: 10};// defrent object: object1 != object3

Context vs Scope

const object4 = {
     a: function() {
         console.log(this);
     }
 }

Classes

class Player {
     constructor(name, type){
         console.log('player', this);
         this.name = name;
         this.type = type;
     }
     introduce() {
        console.log(`Hi I am ${this.name}, I'am a ${this.type}`)
     }
 }
class Wizard extends Player {
     constructor(name, type) {
         super(name, type)
         console.log('wizard', this);
     }
     play() {
         console.log(`Weeeeeee I'am a ${this.type}`);
     }
 }
 const wizard1 = new Wizard('Shelly', 'Healer');
 const wizard2 = new Wizard('shawn', 'Dark Magician');

Pass by reference VS Pass by Value:

  • pass by value creates a new space in the memory
  • pass by reference assign space in the memory to a variable

Create a Clone

let obj = {a: 'a', b: 'b', c: 'c'};
 let obj2 = obj;
 let clone = Object.assign({}, obj);
 let clone2 = {...obj}; //Another way of cloning
 // if we do 
 obj.c  = 5;
 console.log(obj2)//will be effected
 console.log(clone) // will not be effected
 //? Deep cloning:
 let obj = {a: 'a', b: 'b', c: {
     deep: 'try and copy me'
 }};
 let superClone = JSON.parse(JSON.stringify(obj));
console.log(superClone);

Type coercion:

mean the language converting a certain type to another type.

1 == '1'; // True
1 === '1'; // False
  • === : three equals in JavaScript means compare the values. But don’t try and coerce the values, be explicit with your comparison and do exactly what I tell you.
  • ==: double equal sign, simply means compare the two values and if they have different types try to coerce one into the same type.

Advanced loops

???? Let’s work with this array

const basket = ['apples', 'oranges', 'grapes'];
const detailedBasket = {
    apples : 5,
    oranges : 10,
    grapes : 1000
}

➡ For loop

for (let i=0; i < basket.length; i++){
    console.log(basket[i]);
}

➡ forEach

basket.forEach(item => {
    console.log(item);
})

➡ For of:

  • Iterating - arrays, Strings (one by one)
  • both arrays and strings are iterable
for (item of basket){
    console.log(item);
}
for (item of 'basket'){
    console.log(item);
}

➡ For in:

  • loop over objects- properties
  • enumerating - objects
for (item in detailedBasket){
    console.log(item)
}

????‼for of doesn't loop over an object because it's not iterable


ES7 (2016)

includes:

'hellooooo'.includes('o');//? true
const pets = ['cat', 'dog', 'bat'];
pets.includes('dog')//?true

Exponential operator e(x)

const square = (x) => x**2;
const cube = (x) => y**3;

ES8 (2017)

PadStart(), PadEnd():

.PadStart()
'Turtle'.PadStart(10);//=>"     Turtle"
.PadEnd()
'Turtle'.PadEnd(10);//=>"Turtle      "
//* 10 total spaces used inluding the string

Comma at the end of the function:

const fun = (
    a,
    b,
    c,
    d,
) =>{
console.log(a);
}
fun(1,2,3,4,)

Now we can add a comma to the end of a function in order just to make things a little bit cleaner, it's just syntactic and just make things look a little bit nicer.

Object.values & object.entries:

//* In order to turn an object to an array we used Before
Object.keys
//* Now
Object.values
Object.entries 
let obj = {
    username0 : 'santa',
    username1 : 'Rudolf',
    username2 : 'Grinch',
}
Object.keys(obj).forEach((key, index) => {
    console.log(key, obj[key]);
})

Object.values(obj).forEach(value => {
    console.log(value);
})
Object.entries(obj).forEach(value => {
    console.log(value);
})
Object.entries(obj).map(value => {
    return value[1] + value[0].replace('username', '');
})

ES10 (2019)

Flat()

const array = [1,2,[3,4,[5]]];
array.flat()//=> return [1,2,3,4,[5]]
array.flat(2) //=> return [1,2,3,4,5]

const entries = ['bob', 'sally',,,,,,,'cindy'];
entries.flat() //=> ["bob", "sally", "cindy"]

flatMap()

const array2 = array.flatMap(num => num + 5);
//=>[6, 7, "3,4,55"] Map and flat the result to a deep of 1.

TrimStart() & TrimEnd():

const userEmail = 'eddytheeagle@gmail.com'
const userEmail2 = 'nobody@gmail.com'
console.log(userEmail.trimStart())
console.log(userEmail2.trimEnd())

FromEntries:

userProfiles = [['commanderTom', 23], ['derekZlander', 40], ['hansel', 18]];
Object.fromEntries(userProfiles);//=>{commanderTom: 23, derekZlander: 40, hansel: 18}
const obj = Object.fromEntries(userProfiles);
Object.entries(obj);//=> it give back the userProfiles array

Try ... catch:

//* try something, if there is an error do the inside the catch
try{
    true + 'hi'
}catch{
  console.log('you messed up')
}
//? befor we had to pass a parameter: 
try{
    true + 'hi'
}catch(error){
  console.log('you messed up' + error)
}

Debugging

const flattened =  [[0,1], [2,3], [4,5]].reduce((a,b) => a.concat((b), []));
//* to understand this array 
const flattened =  [[0,1], [2,3], [4,5]].reduce((accumulator,array) => {
    console.log('array', array);
    console.log('accumulator', accumulator);
    return accumulator.concat((array), [])
});
//? Method 2
const flattened =  [[0,1], [2,3], [4,5]].reduce((accumulator,array) => {
   debugger;
    return accumulator.concat((array), [])
}); //in order to see what happen step by step

Modules

????JavaScript file 1

//js1:
export const add1 = (a,b) => a + b;
//or
export default function add2(a, b) {
    return a + b;

???? JavaScript file 2

//js2
import {add} from './add1';
//or
import add from './add2';

JSON-AJAX

JSON

JavaScript Object Notation JSON is a syntax for storing and exchanging data. JSON is text, written with JavaScript object notation.

JSON vs XML syntax

everything needs to be a string
JSON can be understood by any server language.
Javascript come with its own functions:

JSON.parse(); //turn a JSON to an object
var obj = JSON.parse('{"name":"John","age":30, "city":"New York"}');
JSON.stringify();//turn an object to JSON
var myJSON = JSON.stringify(obj);

Originally, the only way to submit some form data to a server was through the <form> tag in HTML. As we have learned, it can do a POST or a GET request. With JSON you can now grab the contents of the <input> in a form and submit those with JSON instead of as a form data. You can now submit to the server whenever you want without it necessarily being a <form>, through AJAX.

AJAX:

It allows us to read from a web server after the page has loaded and updated a web page without reloading the page. And finally, send data in the background while the user is interacting with the Website.

???? The new Way: Fetch

fetch('/my/url').then(response => {
   console.log(response);
});

???? Example:

myAjaxfunction() {
   fetch('https://jsonplaceholder.typicode.com/users')
     .then(response=> response.json())//return a promise
     .then(data => console.log(data));//return an object
 }

Ajax is a combination of tools of using the fetch API, using HTTP, using JSON to communicate with servers.


Promises

A promise is an object that may produce a single value sometime in the future. Either a resolved value or a reason that it's not resolved or rejected. A promise maybe in one of three possible states fulfilled, rejected, or pending.

before Promise

???? Example 1

el.addEventListener("click", submitForm);

???? Example 2

// callback pyramid of dom
movePlayer(100, 'Left', function(){
   movePlayer(400, 'Left', function(){
       movePlayer(40, 'Right', function(){
           movePlayer(330, 'Left', function() });
       });
   });
})

with Promise

movePlayer(100, 'left')
  .then(() => movePlayer(400, 'Left'))
  .then(() => movePlayer(40, 'Right'))
  .then(() => movePlayer(330, 'Left'))

Creating a Promise

const promise = new Promise((resolve, reject) => {
   if (true) {
       resolve('Stuff Worked');
   }else {
       reject('Error, it broke')
   }
})
// One line
promise.then(result => console.log(result));
// Multiple lines
promise
 .then(result => result + '!')
 .then(result2 => {
     console.log(result2);
 })

Catching an Error

const promise = new Promise((resolve, reject) => {
   if (true) {
       resolve('Stuff Worked');
   }else {
       reject('Error, it broke')
   }
})

promise
 .then(result => result + '!')
 .then(result2 => {
     throw Error
     console.log(result2);
 })
 .catch(() => console.log('Errooor!'))

The error needs to happen before catch, otherwise, it won't run.

Promise for Asynchronous programming

promises are great for asynchronous programming. When you don't want javascript to block the execution of your code like making API calls, grabbing data from a database, or maybe optimizing an image you use a promise so that the task happens in the back. when the promise gets resolved or rejected then you'll get that response.

const promise = new Promise((resolve, reject) => {
   if (true) {
       resolve('Stuff Worked');
   }else {
       reject('Error, it broke')
   }
})

const promise2 = new Promise((resolve, reject) => {
   setTimeout(resolve, 100, 'HIII')
})
const promise2 = new Promise((resolve, reject) => {
   setTimeout(resolve, 1000, 'POOKIE')
})
const promise2 = new Promise((resolve, reject) => {
   setTimeout(resolve, 5000, 'Is it me you are looking for?')
})
Promise.all([promise, promise2, promise3, promise4])
.then(values => {
     console.log(values);
 })

it took 5 seconds in order to execute, because Promise.all() execute according to the longest, which in this case 5 seconds.

Example in a real-time scenario

const urls = [
    'https://jsonplaceholder.typicode.com/users'
    'https://jsonplaceholder.typicode.com/posts'
    'https://jsonplaceholder.typicode.com/albums'
]

Promise.all(urls.map(url => {
    return fetch(url).then(resp => resp.json())
})).then(results => {
      console.log(results[0])
      console.log(results[1])
      console.log(results[2])
  }).catch(() => console.log('Error!'))
  //to catch an error if there's one.

So at their most basic promises are a bit like event listeners except a promise can only succeed or fail once it cannot succeed or fail twice. And this is extremely useful for things that are asynchronous. Success and failure such as API call because we're less interested in the exact time something became available and more interested in reacting to the outcome. So we're reacting to something that happens asynchronously.


ES8-ASYNC AWAIT

Async Await is part of ES8 and is built on top of promises. Now underneath the hood an async function is a function that returns a promise. But the benefit of Async Await is that it makes code easier to read.

With Promise

movePlayer(100, 'left')
  .then(() => movePlayer(400, 'Left'))
  .then(() => movePlayer(40, 'Right'))
  .then(() => movePlayer(330, 'Left'))

With ASYNC AWAIT

async function playerStart(){
   const firstMove = await movePlayer(100, 'Left');//pause
   await movePlayer(400, 'Left');//pause
   await movePlayer(10, 'Left');//pause
   await movePlayer(330, 'Left');//pause
}

The goal with async-await is to make code look synchronous - a code that's asynchronous look synchronous. async-await code are just promises. Underneath the hood, we call this 'syntactic sugar' something that still does the same thing but is just different syntax to make it look prettier.

async function playerStart(){
   const first = await movePlayer(100, 'Left');//pause
   const second = await movePlayer(400, 'Left');//pause
   await movePlayer(10, 'Left');//pause
   await movePlayer(330, 'Left');//pause
}

Now the cool thing about this is that instead of chaining it like this I can now assign just like asynchronous programming, variable first to await this, and I can assign second to await this and first and second, will have the result of each function but in a variable. So it looks very synchronous. You're not using '.then' you're not chaining.

More realistic example

???? Example 1

//promise
    fetch('https://jsonplaceholder.typicode.com/users')
    .then(resp => resp.json())
    .then(console.log)
// ASYNC AWAIT
    async function fetchUsers(){
    const resp = await fetch('https://jsonplaceholder.typicode.com/users')
    const data = await resp.json();
    console.log(data);
}

???? Example 2

// promise
const urls = [
    'https://jsonplaceholder.typicode.com/users'
    'https://jsonplaceholder.typicode.com/posts'
    'https://jsonplaceholder.typicode.com/albums'
]

Promise.all(urls.map(url => {
    return fetch(url).then(resp => resp.json())
})).then(results => {
      console.log(results[0])
      console.log(results[1])
      console.log(results[2])
  }).catch(() => console.log('Error!'))

// ASYNC AWAIT
const getData = async function() {
    try {
    const [ users, posts, albums ] = await Promise.all(urls.map(url => fetch(url).then(resp => resp.json())))
    console.log('users', users)
    console.log('posts', posts)
    console.log('albums', albums)
    } catch(error) {
        console.log('oops, error!', error)
    }
// it's important to give catch a parametre 'error'
}

setState

You can call a function after the state value has updated:

this.setState({foo: 'bar'}, () => { 
    // Do something here. 
});

Also, if you have lots of states to update at once, group them all within the same setState:

Instead of:

this.setState({foo: "one"}, () => {
    this.setState({bar: "two"});
});

Just do this:

this.setState({
    foo: "one",
    bar: "two"
});

ES9 (2018)

Object spread operator

const animals = {
    tiger: 23,
    lion : 4,
    monkey: 2,
    bird: 40
}
function objectSpread(p1, p2, p3) {
    console.log(p1)
    console.log(p2)
    console.log(p3)
}
const {tiger, lion, ...rest} = animals;
objectSpread(tiger, lion, rest);

This return 23, then 5, then {monkey: 2, bird: 40}

ES9 ASYNC

???? finally:

finally is great for those times that you need to run a piece of code no matter what After a promise, perhaps you want to send an email to a user regardless of whether their request was successful or failed. Maybe you want to have a little notification icon. There are many ways to use finally and now there is a way to make sure that something happens after a promise.

const urls = [
    'https://swapi.co/api/people/1'
    'https://swapi.co/api/people/2'
    'https://swapi.co/api/people/3'
    'https://swapi.co/api/people/4'
]

Promise.all(urls.map(url => {
    return fetch(url).then(people => people.json())
})).then(array => {
    throw Error;
      console.log('1', array[0])
      console.log('2', array[1])
      console.log('3', array[2])
      console.log('4', array[3])
  }).catch(err => console.log('ughhhh fix it!', err))
  .finally(() => console.log('extra'));

finally() will run regardless of what happened before.

???? for await of

const urls = [
    'https://jsonplaceholder.typicode.com/users'
    'https://jsonplaceholder.typicode.com/posts'
    'https://jsonplaceholder.typicode.com/albums'
]

// ASYNC AWAIT
const getData = async function() {
    try {
    const [ users, posts, albums ] = await Promise.all(urls.map(url => fetch(url).then(resp => resp.json())));
    console.log('users', users)
    console.log('posts', posts)
    console.log('albums', albums)
    } catch(error) {
        console.log('oops, error!', error)
    }

}
// For await of
const getData2 = async function() {
    const arrayOfPromises = urls.map(url => fetch(url));
    for await (let request of arrayOfPromises) {
        const data = await request.json();
        console.log(data)
    }
}

The only thing that the for await of feature does it allows us to loop through these multiple promises almost as if we're writing synchronous code. So to review we have the finally function that we can run at the end of a promise and we have the for await of that takes each item from an array of promises that returns to us in the correct order.

Leave a comment

Your email address will not be published. Required fields are marked *