JavaScript et TypeScript

vue d'ensemble

/

Objectifs

Prérequis pour les formations CGI:

  • Browser
    • DOM, Ajax...
  • langage JS
  • POO en JS
  • asynchronisme en JS
  • langage TS
  • Ecosysteme
    • npm
    • web frameworks
    • Hybrid et Ionic

Les navigateurs

  • fonctionnement
  • fonctionnalités
  • comme outil de développement

Le web aujourd'hui...

le navigateur...

Browser

Rendering engine

APIs

JavaScript Engine

// initialise le DOM

// accès au DOM

// accès à AJAX

// ...

le DOM et (beaucoup) d'APIs

Un IDE parfait...

Une philo...

(liée aux coûts de dev.)

Contenu

Comportement

Style

lançant des... IDEs

en ligne...

La partie pas cool...

JavaScript

Création

  • créé en 1995
  • standardisé en ECMAScript (ECMA-262)
  • version actuelles:
    • ES5.1 : 2011
    • ES6 : 2015

Aujourd'hui

  • 12 millions de dev...
  • rendu rapide par V8
  • plus grand repo logiciel (tous langages confondus)

Les variables

  • containers pour des "valeurs"
  • garbage collector.
  • les variables ne sont pas typées.
    • MAIS, les valeurs, SI
    • dynamiquement typé
  • il existe 3 façons de déclarer une variable:
    • const: à privilégier (lecture seulement)
    • let: déclaration "liée au block".
    • var: ...

Les valeurs

  • les opérateurs ont la vilaine manie de caster les valeurs... (weakly typed)
  • l'opérateur "typeof()" retourne le type d'une valeur
  • il existe exactement 6 types (de valeurs):
    • Undefined: undefined
    • Null: null
    • Boolean: true, false
    • Number: 42 .33 NaN Infinity
    • String: "double quoted" or 'single quoted'
    • Object:
1 + "1"

Les objets

les objets sont des références vers des

"dictionnaires / tableaux associatifs / tables de hachage"

object_var

ref: 0x123456

string_var

"ma chaine de caractères"

addr: 0x123456

x
y

"une autre chaine"

42

object_var2

ref: 0x123456

Les objets

les objets sont des collections de propriétés.

les propriétés sont des containers pour des valeurs...

// variable and primitive value
let x = "Hello";

// variable et objet
let tab = {
  y: "test",
  z: 42
};

x;        // "Hello"
tab;      // (the object ref)
tab.y;    // "test"
tab["y"]; // "test"

tab.y === tab["y"];  // true (NB: triple equal)

initialisation des objets

les objets sont mutables (toujours):

let x = {
  prop1: "a",
  prop2: 42
}

let y = x;
let z = new Object();

z.prop1 = "a";
z.prop2 = 42;

Object.is(x,y)
Object.is(x,z)

x === y // ???
x === z // ???

Les tableaux

  • Les tableaux sont des objets (de type "Array")
  • indexés à partir de 0
  • stockent des valeurs hétérogènes.
var arr = [ "test", 1234, {}, [], "hi" ];

arr.push("sixth"); // 6
arr.length;        // 6
arr[5];            // "sixth"

arr[7] = 012;      // 10
arr.length;        // 8

arr[6];            // undefined
arr[7];            // 10

arr[8];            // undefined
arr.length;        // 8

Les tableaux

(et les boucles)

// les tableaux se parcourent avec .forEach()
let fruits = ['Apple', 'Banana'];

fruits.forEach(function(item, index, array) {
  console.log(item, index);
});
// Apple 0
// Banana 1

// ou "for...of"
for (let f of fruits){
  console.log(f.length)
}

Les tableaux

(et les boucles)

// les tableaux se parcourent avec .forEach()
let fruits = ['Apple', 'Banana'];

fruits.forEach(function(item, index, array) {
  console.log(item, index);
});
// Apple 0
// Banana 1

// ou "for...of"
for (let f of fruits){
  console.log(f.length)
}
/*******************
 *    ATTENTION    *
 * *****************/
// les propriétés sont parcourues avec for...in

let obj = {x:1, y:2};

for (let prop in obj){
  console.log(prop);
}

// x
// y

Les fonctions

  • Les fonctions sont des objets (de type "Function")
  • les signatures ne sont PAS vérifiées.
function add(x,y){
  return x+y;
}

add(1,2);   // 3 ...
add(1);     // NaN: comme 1 + undefined
add(1,2,3); // 3 (outch)
// fonctions variadiques
function add(){
  let s = 0;
  for (let arg of arguments){
    s += arg
  }
  return s;
}

// ou (plus moderne)
function add(...args){
  let s = 0;
  for (let arg of args){
    s += arg
  }
  return s;
}

Les fonctions

les closures (ou "fermetures lexicales")

Une fonction peut compter sur plusieurs variables prédéfinies:

  • les arguments (y compris la variable "arguments")
  • this (wait for it...)
  • TOUTES les variables de son scope et des scopes parents.

Les fonctions

les IIFEs

Une fonction est souvent définie pour un usage immédiat.

(et profiter des closures)

On appelle ça une Immediately Invoked Function Expression

// on voudrait raccourcir:
function toto(){console.log("toto");}
toto();

// en
function toto(){console.log("toto");}();

// mais en fait, il faut faire ça...
(function toto(){console.log("toto");})();

les fonctions fléchées

"arrow functions"

let tab = [1,2,3,4]

tab.forEach(function (i){
  console.log(i+1);
});
let tab = [1,2,3,4]

tab.forEach((i) => {console.log(i+1);});
tab.map((i)=>i+1).forEach((i)=>console.log(i));

// les arrows functions peuvent se passer d'accolades
// et de return
// si la partie droite est une expression (pas une instruction) 

Ne sont pas "hoisted"...

let vs var

(un problème de fermeture lexicale)

for (let i = 0; i < 10; i++) {
  setTimeout(() => {
    console.log(i);
  }, 1);
}

> 0
> 1
> 2
...
for (var i = 0; i < 10; i++) {
  setTimeout(() => {
    console.log(i);
  }, 1);
}

> 10
> 10
> 10
...

la gestion des exceptions

  • les erreurs sont ... des objets. (de type "Error")
  • propriétés:
    • message
    • fileName
    • lineNumber
  • beaucoup d'erreurs standards
  • sinon, c'est comme en Java.
try {
  nonExistentFunction();
} catch (error) {
  console.error(error);
  // expected output: ReferenceError: nonExistentFunction is not defined
  // Note - error messages will vary depending on browser
}

La programmation orientée objet

(la partie ardue)

JavaScript

La POO en JS

souvent: "OOJS"

  • JS est un langage où TOUT est objet.
    • vous aviez remarqué
  • Mais c'est un langage sans vraies classes !!!

le prototypage

  • JS est un langage orienté "prototype".
  • ce mécanisme remplace les classes et l'héritage.
  • quand on tente d'accéder à une propriété sur un objet, l'objet est inspecté en premier lieu. Si absente, on tente d'accéder à cette propriété sur son prototype...
    • (et récursivement... jusqu'à "Object")

Définir ses propres types

function Meme(name, url){
  this.name = name;
  this.url  = url;
  this.funLevel = 5;
}

let disasterGirl = new Meme("Disaster Girl", "https://i.imgflip.com/4yionv.jpg")

Avec ses méthodes

Meme.prototype.sayHello = function sayHello(){
  console.log("Hello, my name is " + this.name);
};

disasterGirl.sayHello();
// Hello, my name is Disaster Girl

Mais c'est quoi au juste un prototype?

un dessin?

disasterGirl Meme Function Meme Object Object Function Object Object .prototype .__proto__ Object.getPrototypeOf() Object.setPrototypeOf() .constructor .prototype .__proto__ Object.getPrototypeOf() Object.setPrototypeOf() .constructor

un exemple?

function Meme(name, url) {
  this.name = name;
  this.url = url;
  this.funLevel = 5;
}

let disasterGirl = new Meme(
  "Disaster Girl",
  "https://i.imgflip.com/4yionv.jpg");
  
Meme.prototype.sayHello = function sayHello(){
  console.log("Hello, my name is " + this.name);
};
 
disasterGirl.__proto__; // an object with a "sayHello" property
disasterGirl.constructor === Meme;  // true
disasterGirl.constructor.prototype === disasterGirl.__proto__; // true

disasterGirl.__proto__.__proto__ === Object.prototype; // true ^^
disasterGirl.__proto__.__proto__.constructor === Object; // true

"this" is a trap...

  • "this" fonctionne différemment en JS.
  • Il représente l'objet "sur lequel est appelé la fonction".
// en théorie tout va bien

function Person(name){
  this.name = name;
}

Person.prototype.sayHello = function (){
  console.log("Hello, my name is " + this.name);
}

let toto = new Person("Toto");
toto.sayHello(); // "toto" devient "this"

"this" is a trap...

Vous connaissez la différence entre la théorie et la pratique? :p

let say = toto.sayHello;

say() // TypeError: "this" is undefined

///////////////////////////
// sinon, on peut faire ça:
// 

say.call(toto);

// ou ça:

let totoHello = Person.prototype.sayHello.bind(toto);
totoHello();
totoHello();
function CategorizedMeme(name, url, category) {
  Meme.call(this, name, url);
  this.category = category;
}

let meme2 = new CategorizedMeme('Distracted Boy', 'myurl', 'funny');

meme2.category === 'funny';
meme2.name     === 'Distracted Boy';
meme2.funLevel === 5;

meme2.sayHello === undefined; //  (╯°□°)╯ ︵ ┻━┻

Object.setPrototypeOf(
  CategorizedMeme.prototype, 
  Meme.prototype
);

meme2.sayHello();  // inheritance... at last

et si on devient...

Hahaha, je vous ai eu...

class Toto{
  constructor(name){
    this.name = name;
  }
}

let toto = new Toto("Toto");

toto.constructor.prototype === toto.__proto__;  // true

class Titi extends Toto{
  constructor(name, x){
    super(name);
    this.x = x;
  }
}

let titi = new Titi("Titi", 42);

titi.__proto__.__proto__.constructor === Toto

Merci ES6...

Retour à la maison...

class Person{
  
  constructor(firstName, lastName){
    this.firstName = firstName;
    this.lastName  = lastName;
  }
  
  // methodes
  sayHello(){
    console.log("Hello, I'm " + this.firstName);
  }
  
  // static 
  static staticProperty = 'someValue';
  static staticMethod() {
    return 'static method has been called.';
  }

  // accesseurs
  get completeName(){
    return this.firstName + " " + this.lastName;
  }
}

L'objet global

  • dans les navigateurs, c'est "window"
  • dans nodeJS, c'est "global"
  • "window" permet d'accéder à la fenêtre du navigateur
  • "window.document" permet d'accéder au DOM
    • souvent abrégé en "document"

Modification du DOM

  • document.querySelector()
  • document.createElement()
  • element.textContent
  • element.appendChild()
  • element.parentNode
  • element.setAttribute()
    • surtout "class"
  • ...

L'héritage multiple

(les mixins)

let calculetteMixin = Base => class extends Base {
  calc() { }
};

let aleatoireMixin = Base => class extends Base {
  randomiseur() { }
};

class Toto { }
class Truc extends calculetteMixin(aleatoireMixin(Toto)) { }

(j'étais obligé...)

  • les classes peuvent être anonymes
    • (comme les fonctions)
  • générer les classes dynamiquement permet de "contourner" les limitations.

L’asynchronisme

(la partie cool)

JavaScript

C'est quoi "asynchrone"?

  • Une forme d’exécution de plusieurs tâches en concurrence.
    • (pas de parallélisme)
  • collaboration active des tâche pour éviter bloquer le thread unique.
  • tâches misent en file d'attente.

Le tuto officiel est un bijou

(Je ne ferais pas mieux que ça...)

Le langage

  • JS n'est pas "asynchrone" en soi.
    • c'est un langage impératif
  • Ce sont ses librairies qui le rendent ainsi.
    • du fait de son usage de départ (le navigateur)
    • (mono-thread)
  • Toutes les I/O sont non-bloquantes.

Attendre...

let myTimeout = setTimeout(
  ()=>{console.log("now!")}, 
  2000,
);

let myInterval = setInterval(
  ()=>{console.log("now!")}, 
  2000,
);

clearTimeout(myTimeout);
clearInterval(myInterval);

Les callbacks

premier mécanisme de gestion asynchrone

let tacheLongue = ()=>{
  setTimeout(
    ()=>{
      console.log("c'était long...")
    },
    2000
  );
}

let txt = "je veux exécuter ça APRES!"
tacheLongue();
console.log(txt);
let tacheLongue = (cb)=>{
  setTimeout(
    ()=>{
      console.log("c'était long...");
      cb();
    },
    2000
  );
}

let txt = "je veux afficher ça APRES!";
tacheLongue(()=>{
	console.log(txt);
});

error-first callbacks

let tacheLongue = (cb)=>{
  try {
    setTimeout(
      ()=>{
        console.log("c'était long...");
        cb();
      },
      2000
    );
  } catch (error){
    cb(error);
  }
}

let txt = "je veux afficher ça APRES!";
tacheLongue((err)=>{
  if (err){
    console.log("Oups");
    return;
  }
  console.log(txt);
});

Les Promises

Les Promises

  • second mécanisme de gestion de l'asynchronisme.
  • un objet encapsulant un traitement en cours.
let done = true;

let maPromise = new Promise((resolve, reject)=>{
  setTimeout(
    () => {
      if (done)
        resolve("done était vrai")
      else
        reject("done était faux")
    },
    2000,
  );
});

maPromise
  .then(resultat1 => '""" ' + resultat1 + ' """' )
  .then(resultat2 => {console.log('au final: ' + resultat2)})
  .catch(raison => {console.log('raté: ' + raison)})

async/await

  • s'est juste un usage de Promise intégré dans la syntaxe.
    • pas un nouveau mécanisme
    • (OK, JS est un petit peu un "langage asynchrone" maintenant...)
  • une "async" fonction asynchrone renvoie TOUJOURS une Promise
    • implicitement ou pas...
  • dans les fonctions "async", on peut utiliser "await".
    • qui revient à utiliser ".then()"
    • un try...catch correspond à un ".catch()"

et tout redevient lisible...

let done = true;

let maPromise = new Promise((resolve, reject)=>{
  setTimeout(
    () => {
      if (done)
        resolve("done était vrai")
      else
        reject("done était faux")
    },
    2000,
  );
});

maPromise
  .then(resultat1 => '""" ' + resultat1 + ' """' )
  .then(resultat2 => {console.log('au final: ' + resultat2)})
  .catch(raison => {console.log('raté: ' + raison)})

et tout redevient lisible...

let done = true;

let maPromise = new Promise((resolve, reject)=>{
  setTimeout(
    () => {
      if (done)
        resolve("done était vrai")
      else
        reject("done était faux")
    },
    2000,
  );
});

maPromise
  .then(resultat1 => '""" ' + resultat1 + ' """' )
  .then(resultat2 => {console.log('au final: ' + resultat2)})
  .catch(raison => {console.log('raté: ' + raison)})
let done = true;

async function traitement1(){
  if (done)
    return "done était vrai"
  else
    throw "done était faux"
}

async function traitement2(){
  try {
    let resultat = await traitement1();
    console.log('""" ' + resultat + ' """')
  } catch (raison) {
    console.log('raté: ' + raison)
  }
}

traitement2();

(enfin, ça a l'air synchrone quoi...)

Où est le .setTimeout()?

  • .setTimeout() utilise une callback, pas une Promise.
  • il faut le "promisifier"
function later(delay){
  return new Promise(resolve => setTimeout(resolve, delay))
}

async function process(){
  await later(2000);
  console.log("TADAAAAAA!!!");
}

process();

// ou, avec nodeJS
let util = require('util')
let later = util.promisify((delay, f) => setTimeout(f, delay))

// fait pour les fonctions dont la callback est le dernier argument
// comme toujours en NodeJS

AJAX

  • Définition...
  • lié aux I/O donc -> asynchrone
  • les navigateur ont une API "fetch"

Event handlers

Object destructuring

TODO

@Decorators

TODO

"JavaScript that scales"

TypeScript

C'est quoi TypeScript?

  •  Un superset strict de JS
    • dans sa dernière version
    • avec des types
    • "transpile" dans la version de JS désirée
  • absorbe désormais l'essor de JS
  • "nécessaire" pour certains frameworks.
    • notamment Angular

Import / export

c'est compliqué...

Ecosystème

et frameworks

Pourquoi j'ai besoin de nodeJS?

(je veux faire une app cliente moi...)

Angular

npm install -g @angular/cli
ng new testNG
cd testNG

RxJS

(C'est quoi la programmation reactive?)

RxJS

C'est quoi une app "hybride"?

Ionic

npm install -g @ionic/cli
ionic start testIonic tabs
cd testIonic

VSCode

et le dev. en remote

SSH serveur fr02-9900wl4cli
port 2201
user node
pasword node

Learn by doing...

Merci de votre attention

JS/TS

By Olivier DUPOUY

JS/TS

knowledge about front-end languages and basic tools.

  • 107