Javascript reloaded

NodeJS #1

Whois

Julien Herpin

Frontend Lead Developer @

Actuellement en mission chez Canal+

Au programme

ES2015,

ExpressJS,

MongoDB,

Jade / Stylus,

Mocha / Chai / Sinon, ...

Découverte de NodeJS mais aussi...

Mais d'abord...

Types primitifs,

Objets,

Tableaux,

ES2015,

Closures,

Promesses, ...

Quelques rappels en Javascript

ECMAScript

Versions

Variables

var x = 5;
const x = 5; // single-assignment
let y = 3; // "let" is the new "var"

ES6

Before

Variables

function varnish() {
  //nish *is* visible out here
  for( var nish = 0; nish < 5; nish++ ) {
    //nish is visible to the whole function
  };
  //nish *is* visible out here
};
function letuce() {
  // tuce is *not* visible out here
  for( let tuce = 0; tuce < 5; tuce++ ) {
    // tuce is only visible in here (and in the for() parentheses)
  };
  // tuce is *not* visible out here
};

ES6

Before

Block scope

Variables

Block scope

Types de données

  • Six types de données primitifs:
    • booléen (boolean)
    • null
    • undefined
    • nombre
    • chaînes de caractères (strings)
    • Symbol (un nouveau type introduit avec ECMAScript 6)
  • et le type Object

Types de données

Le type nul (null)

Le type nul ne possède qu'une valeur : null.

null === undefined // false
null == undefined // true
null === null // true

null VS undefined

var bar = null;
var foo = undefined; // ou var foo;

Le type indéfini (undefined)

Une variable à laquelle on n'a pas affecté de valeur.

Attention !

Types de données

Valeur unique primitive et immuable.

var bar = Symbol();
var foo = Symbol('foo'); // Optional description for debugging

console.log(bar); // ==> Symbol()

symbol (es6)

Type object

Un object est une collection de propriétés

// Initialisation
var car = { year: 2006, color: 'red' };

// Ecriture
car.brand = 'BMW';
car['brand'] = 'BMW'

// Lecture
console.log(car.brand);
console.log(car['brand']);

Type object

Plus intelligent en ES6

var foo = 'bar';

var obj = {
    // Shorthand, pareil que ‘foo: foo’
    foo,

    // Méthodes
    toString() {
     return "a string";
    },
 
    // Computed (dynamic) property names
    // Comme var obj = {}; obj[foo] = 42;
    [ foo ]: 42 
};

Type object

On peut utiliser une fonction constructeur

Voiture.demarre = function() {
  console.log('vroum');
};

Voiture.demarre();

Objet instanciable

Et définir des méthodes 

function Voiture(fabricant, modèle, année) {
  this.fabricant = fabricant;
  this.modèle = modèle;
  this.année = année;
}

var maVoiture = new Voiture("Eagle", "Talon TSi", 1993);

Type object

Il vaut mieux utiliser le prototype

Prototype

function Voiture(fabricant, modèle, année) {
  // ...
}

Voiture.prototype.demarre = function() {
  console.log('vroum');
}

var maVoiture = new Voiture();
var maVoiture2 = new Voiture();
maVoiture.demarre();

// maVoiture.demarre === maVoiture2.demarre ==> true

Type object

Copier les valeurs de toutes les propriétés directes d'un objet sur un autre objet cible

Object.assign

Object.assign(target, ...sources)
var obj = { a: 1 };
var copie = Object.assign({}, obj)
console.log(copie); // {a: 1}

Cloner un objet

var o1 = { a: 1 };
var o2 = { b: 2 };
var o3 = { c: 3 };

var obj = Object.assign(o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3 }
console.log(o1); // { a: 1, b: 2, c: 3 }

Merger des objets

const zoo = {
  lions: 2,
  tigers: 3,
};

const home = {
  cats: 1,
  dogs: 2,
};

// 1) Ajouter 5 lapins dans "home"  

// 2) Fusionner les 2 objets pour n'en faire qu'un !
// -> const animals = { lions: 2, tigers: 3, cats: 1, dogs: 2, rabbits: 5 };

// Attention : 
// console.log(zoo) et console.log(home)
// ne doivent pas être altérés après la fusion !!!

// 3) Afficher les noms d'animaux dans un tableau

// 4) Afficher le nombre total d'animaux en itérant sur l'objet "animals"

Type object

exercice

Arrays

Les tableaux JavaScript sont des objets semblables à une liste

var annees = [2000, 2010];
console.log(annees[0]); // 2000

// Ajout (push, shift)
annees.push(2020);
console.log(annees); // [2000, 2010, 2020]

// Taille (length)
console.log(annees.length); // 3

// Retrait (pop et shift)
var last = annees.pop();
console.log(last); // 2020

var first = annees.shift();
console.log(first); // 2000

console.log(annees.length); // 1

Arrays

Joindre des éléments (join) => inverse avec split

var a = ['a', 'e', 'i'];
var str = a.join(', ');
console.log(str) // => 'a, e, i'
var tableau = [2, 9, 9];
tableau.indexOf(2);     // 0
tableau.indexOf(7);     // -1

Trouver un élément (indexOf)

Utilities

function logArrayElements(element, index, array) {
    console.log("a[" + index + "] = " + element);
}
[2, 5, , 9].forEach(logArrayElements);

Boucler (forEach)

Arrays

map

var nombres = [1, 4, 9];
var doubles = nombres.map(function(num) {
  return num * 2;
});
// doubles vaut désormais [2, 8, 18]. nombres vaut toujours [1, 4, 9]
var reduced = [0, 1, 2, 3, 4].reduce(function(valeurPrecedente, valeurCourante){
  return valeurPrecedente + valeurCourante;
});

// reduced vaut 10

reduce

 

Utilities

Arrays

filter

function suffisammentGrand(element) {
  return element >= 10;
}
var filtre = [12, 5, 8, 130, 44].filter(suffisammentGrand);
// filtre vaut [12, 130, 44]
const colors1 = ['pink', 'green'];
const colors2 = ['red', ...colors1, 'yellow'];

// colors2 ==> ['red', 'pink', 'green', 'yellow'] 

colors2.push(...['blue', 'black']);

// colors2 ==> ['red', 'pink', 'green', 'yellow', 'blue', 'black'] 

spread (es6)

 

Utilities

var people = [
  { name: "Thomas", age: 23 },
  { name: "Marie", age: 28 },
  { name: "Groot", age: 32 },
  { name: "Bob", age: 24 }
];

// 1) Faire la somme des âges

// 2) Retourner une copie du tableau avec une clé "toString"
// qui retourne "Nom-Age". Exemple : "Thomas-23"

// 3) Retourner une copie du tableau sans les âges inférieurs à 25

Arrays

exercice

Classes

"It is just a new way to define prototype-based inheritance"

ES6

class TodoItem extends Component {
  constructor(props, context) {
    super(props, context);
    this.state = {
      editing: false
    };
  }

  handleDoubleClick() {
    super.handleDoubleClick();
    this.setState({ editing: true });
  }
  
  static doIt() {
    console.log('do it');
  }

}
// Convertir en classe ES6

var Vehicle = function(color) {
  this.color = color;
}

Vehicle.prototype.toString = function() {
  return 'my car is' + this.color;
}

Vehicle.log = function() {
  console.log('Vehicle class');
}

// --- Test ---
var v = new Vehicle('blue');
console.log(v.toString());
Vehicle.log();
// --- /Test ---

Classes

exercice

Destructuring

Objects

var obj = {
  a: 'a',
  b: { foo: 'foo' },
};
var a = obj.a; // ==> 'a'
var foo = obj.b.foo; // ==> 'foo'
var undef = obj.c; // ==> undefined
const { a, b } = obj;
const { foo } = obj.b;
const { foo: foofoo } = obj.b; // renaming
const { c } = obj; // invalid prop

console.log(a); // ==> 'a'
console.log(b); // ==> { foo: 'foo' }
console.log(foo); // ==> 'foo'
console.log(foofoo); // ==> 'foo'
console.log(c); // ==> undefined [Soft failing]

For a given object

With ES6 destructuring (—harmony-destructuring)

Destructuring

Objects

render() {
  const { hasError, type, code } = this.props.currentError;
  return (
    <Modal isOpen={ hasError }>
      <div>
        <p>{ code }</p>
        <p>{ this.getMessage(code, type) }</p>
      </div>
    </Modal>
  );
}

Example

Destructuring

Arrays

var [a, , b] = [1, 2, 3];
console.log(a); // ==> 1
console.log(b); // ==> 3
let a = 3;
let b = 5;

[a, b] = [b, a];

console.log(a); // 5
console.log(b); // 3

For a given array

Switch vars

Arrow functions

ES6

var a1 = a.map(function(s){ return s.length });
var a2 = a.map( (s) => s.length );
var a3 = a.map( s => s.length );
function Personne() {
  var self = this;
  self.age = 0;

  setInterval(function grandir() {
    self.age++;
  }, 1000);
}

Same same ! (presque)

Contexte (this)

function Personne() {
  this.age = 0;

  setInterval(() => {
    this.age++;
  }, 1000);
}

Template string

ES6

const name = 'John';

console.log(`${name} is fun`)
// => 'John is fun'

// Multi-ligne !
var markup = `<li>
  ${name} is great
</li>`;

Closures

"use strict";

const fn = function(value) {
  return function(val) {
    return val + value;
  }
}

let v = 5;
const closure = fn(v);

closure(3); // ==> vaut 8
v = 3;
closure(3); // ==> Quelle est la valeur ?

Le principe d'une variable est que sa valeur peut varier d'un instant à l'autre, mais il arrive que l'on ait besoin de conserver cette valeur telle qu'elle est à un moment donné pour l'utiliser plus tard.

for(var i = 0; i < 3; i++) {
  setTimeout(function() {
    console.log(i);
  }, 1000);
}

Closures

exercice

Que retourne l'exemple suivant ?

Trouver une solution à la problématique grâce aux closures !

...

Et sans closure ?

Promises

Async VS Sync

Promises

Avoid callback hell

Promises

Mieux !

var floppy = require('floppy');

floppy.load('disk1')
  .then((data1) => floppy.prompt('Please insert disk 2'))
  .then(() => floppy.load('disk2'))
  .then((data2) => floppy.prompt('Please insert disk 3'))
  .then(() => floppy.load('disk3'))
  .then((data3) => floppy.prompt('Please insert disk 4'))
  .then(() => floppy.load('disk4'))
  .then((data4) => floppy.prompt('Please insert disk 5'))
  .then(() => floppy.load('disk5'))
  .then((data4) => floppy.prompt('OK!'));

floppy.load() et floppy.prompt() retournent une promesse

Promises

Déclarer une promesse

floppy.load = new Promise(function(resolve, reject) {
  // faire un truc, peut-être asynchrone, puis…

  if (/* tout a bien marché */) {
    resolve("Ces trucs ont marché !");
  }
  else {
    reject(Error("Ça a foiré"));
  }
});

Promises

then

function getPromise(value) {
  return new Promise(function(resolve, reject) {
    setTimeout(function() { resolve(value + 10); }, 1000);
  });
}

getPromise(0)
.then(function(result) {
  return getPromise(result);
})
.then((result) => getPromise(result))
.then(function(result) {
  console.log(result);
});

Que vaut "result" à la fin ?

cf. http://bevacqua.github.io/promisees

Promises

errors

new Promise(function(resolve, reject) {
  setTimeout(function() { reject('Done!'); }, 3000);
})
.then(function(e) { console.log('done', e); })
.catch(function(e) { console.log('catch: ', e); });

// From the console:
// 'catch: Done!'

cf. http://bevacqua.github.io/promisees

Promises

errors chaining

var log = "";
 
function doWork() {
    log += "W";
    return Promise.resolve();
}
 
function doError() {
    log += "E";
    throw new Error("oops!");
}
 
function errorHandler(error) {
    log += "H";
}
doWork()
    .then(doWork)
    .then(doError)
    .then(doWork) // this will be skipped
    .then(doWork, errorHandler)
    .then(verify);
     
  function verify() {
    expect(log).toBe("WWEH");
    done();
}

Promises

en parallèle

var request1 = fetch('/users.json');
var request2 = fetch('/articles.json');

Promise.all([request1, request2]).then(function(results) {
  // Both promises done!
});

Promises

exercice

Avec Codepen (option Babel), écrire une suite de promesses pour :

  • récupérer les acteurs d'un film sur http://www.omdbapi.com (charger jquery ou autre pour les requêtes http).
  • convertir la liste des acteurs en array.
  • trier le tableau des acteurs par ordre alphabétique.
Made with Slides.com