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
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.
[NODEJS] Javascript reloaded (cours 1)
By Julien Herpin
[NODEJS] Javascript reloaded (cours 1)
- 1,034