Ceci est un cours de
Front-end et Back-end
Slides: https://slides.com/antho_loup/deck
Cours et projet inspiré de: https://slides.com/benjichaz/but2
1995 - Créé par Brenden Eich chez Netscape/Mozilla
1997 - Standardiser comme ECMAScript (ES1)
2015 - Version majeur ES6 (ES2015) - Supporté par 99% des navigateurs
Depuis 2015, une nouvelle version chaque année
Source: stackoverflow survey 2023, most popular technology by professional developers
Source: State of JS 2022
// index.html
<!doctype html>
<html lang="fr">
<head>
<meta charset="utf-8">
<title>Apprenons JS</title>
<script src="script.js"></script>
</head>
<body>
</body>
</html>
// script.js
window.addEventListener("load", () => {
let body = document.body;
body.textContent = "Hello world";
});
// Commentaire monoligne
/*
Commentaire
multi
ligne
*/
/**
* Calculates the sum of two numbers.
*
* @param {number} num1 - The first number.
* @param {number} num2 - The second number.
* @returns {number} The sum of num1 and num2.
*/
function addNumbers(num1, num2) {
return num1 + num2;
}
let x = 42; // 42
x = 1337;
// 1337
let y; // undefined
const x = 42; // 42
x = 1337;
// Uncaught TypeError: invalid assignment to const 'x'
// DEPRECATED
var x = 42; // 42
if(true) {
let x = 42;
x; // 42
}
x; // undefined
ES6
OLD
// DEPRECATED
var x = 42; // 42
// ... Complex code
var condition = true;
if(condition) {
var x = 421
}
// x = 421
Ne pas utiliser var
!
Un nom de variable correct peut contenir :
- lettres minuscules (a-z)
- lettres majuscules (A-Z)
- chiffres (0-9)
- caractères dollar ($)
- caractères underscore (_)
Un nom de variable ne commence jamais par un chiffre.
good
GOOD
$Good
_good_
gôöd
b-a-d
-Bad-
84D
Types objets (Object) |
---|
Object |
Array |
Set |
Map |
RegExp |
Function |
... |
Types primitifs |
---|
string |
number |
boolean |
null |
undefined |
symbol |
BigInt |
ES6
ES11
"hello"
1337
true
null
undefined
Symbol(42)
BigInt('1337')
[42, "Hello", true]
{ foo: "bar" }
function f() {}
let x = 1337;
x; // 1337
typeof x; // "number"
x = new Date();
typeof x; // "object"
// Le type peut varier pendant l'exécution
x = new Date();
typeof x; // "object"
x instanceof Date; // true
x instanceof RegExp; // false
// Arithmétique
(2 + 13 - 7) * 2 / 4 % 5
// Affectation
let x = 2 // 2
x += 13 // 15
x -= 7 // 8
x *= 2 // 16
x /= 4 // 4
x %= 5 // 4
// In/Décrémentation
let x = 2 // 2
x++ // 2
++x // 4
x-- // 4
--x // 2
// Logique
true && false // false
true || false // true
// <=> true || (false && false) true
true || false && false
let z = true; !z // false
// Egalité
23 == 23 // true
23 == "23" // true
23 === "23" // false
0 == false // true
0 === false // false
// Non Egalité
23 != 23 // false
23 != "23" // false
23 !== "23" // true
// Inégalité
42 < 32; // false
42 <= 42; // true
42 > 6; // true
17 >= 42; // false
// Birwise
// // AND
3 & 5; // 1
// OR
3 | 5; // 7
// Shift
1 << 3; // 8
let number = getNumber()
if (number > 0) {
console.log("Positive")
} else if (number < 0) {
console.log("Negative")
} else if (number === 42) {
console.log("Life answer")
} else {
console.log("Zero")
}
let color = getColor()
switch (color) {
case "RED":
code = "#f00";
break;
case "GREEN":
code = "#0f0";
break;
default:
code = "#000";
}
let i = 0
while(i < 5) {
doSomething(i)
i++
}
for(let i = 0; i < 5; i++) {
doSomething(i)
}
// condition ? siConditionVraie : siConditionFausse;
let x = age >= 18 ? "Majeur" : "Mineur";
let maVariable;
maVariable; // ?
false
null
undefined
Javascript lance une erreur
let maVariable;
maVariable; // undefined
false
null
undefined
Javascript lance une erreur
Vrai
Faux
Vrai
Faux
Array
string
Function
null
Array
string
Function
null
Que le type d'une variable reste constant dans le temps
Qu'il existe plusieurs classes de type (primitifs, object, etc...)
Que le type d'une variable peut changer après initialisation
Que les variables ne peuvent pas être castées
Que le type d'une variable reste constant dans le temps
Qu'il existe plusieurs classes de type (primitifs, object, etc...)
Que le type d'une variable peut changer après initialisation
Que les variables ne peuvent pas être castées
typeof "42"
?number
object
boolean
string
typeof "42"
?number
object
boolean
string
41 puis 42
42 puis 42
let x = 41;
x++; // ?
x; // ?
41 puis 42
42 puis 42
let x = 41;
x++; // 41
x; // 42
Le nombre de égale pour écrire l'opérateur
Ils font la même chose
=== est plus stricte, il vérifie le type
== est plus stricte, il vérifie le type
Le nombre de égale pour écrire l'opérateur
Ils font la même chose
=== est plus stricte, il vérifie le type
== est plus stricte, il vérifie le type
// Declarations
let a = 42;
let b = 3.;
let c = 3.14;
let d = -20;
let e = 10e5;
let f = 0x20; // 32
let g = Infinity;
let h = -Infinity;
let i = NaN; // Not a Number
let j = +0;
let h = -0;
// Float precision IEEE 754
0.1 + 0.2; // 0.3000000000004
// De Number to String
const x = 42;
String(x); // "42"
// De String à Number
const y = "42";
parseInt(y, 10); // 42
parseFloat(y); // 42
Math.round(100.7); // 101
Math.ceil(12.3); // 13
Math.floor(12.7); // 12
Math.random(); // 0.6493849611386405
const x = "I'm your \"father\"\n";
const y = 'I\'m your "father"\n';
const z = `I'm your "father"\n`;
const x = "foo";
x[0]; // "f"
x[1]; // "o"
x[2]; // "o"
x.length; // 3
// Concaténation d'un String
const x = "Veni";
const y = "vidi";
const z = "vici";
// Performant
x + " " + y + " " + z; // "Veni vidi vici"
// Lisible
`${x} ${y} ${z}`; // "Veni vidi vici"
const x = " JavaScript\n";
x.substring(4, 9); // "vaScr";
x.toUpperCase(); // " JAVASCRIPT\n"
x.toLowerCase(); // " javascript\n"
x.replace("a", "@"); // " J@vaScript\n";
x.replace("a", /@/g); // " J@v@Script\n";
x.indexOf("Java"); // 2
x.indexOf("Vue"); // -1
x.trim(); // "JavaScript";
let str = "Hello, world!"
str.startsWith("Hello") // true
str.endsWith("world!") // false
str.includes("world") // true
str = "abc"
str.repeat(3) // "abcabcabc"
str = "123"
str.padStart(5, "0") // "00123"
str.padEnd(5, "0") // "12300"
const x = /^\d{4} \d{4} \d{4} \d{4}$/g; // Compact
const y = new RegExp("^\d{4} \d{4} \d{4} \d{4}$", "g"); // Performant
const x = "I love JavaScript, Vue.js, Vuex and Vue-router";
x.match(/[A-Z][^, ]+/g); // ["JavaScript", "Vue.js", "Vuex", "Vue-router"]
x.match(/\d/g); // null
NaN
0xffff
7
"1773"
NaN
0xffff
7
"1773"
x = "99"
en number, je peux utiliser ?parseFloat(x)
parseInt(x)
x.toNumber()
parseInt(x, 10)
x = "99"
en number, je peux utiliser ?parseFloat(x)
parseInt(x)
x.toNumber()
parseInt(x, 10)
Math
Mathematics
Math
Mathematics
"hello" . "world"
String("hello", "world")
"hello" + "world"
"hello".concat("world")
"hello" . "world"
String("hello", "world")
"hello" + "world"
"hello".concat("world")
/maRegex/.match("foo")
"foo".match(/maRegex/)
match(/maRegex, "foo"/)
"maRegex".includes("foo")
/maRegex/.match("foo")
"foo".match(/maRegex/)
match(/maRegex, "foo"/)
"maRegex".includes("foo")
let x = [1, 2, 3];
let y = ["Hello", true, 42, {foo: "bar"}];
let z = [[1,2,3], [4,5,6]];
let x = [1, 2, 3];
x[0]; // 1
let y = ["Hello", true, 42, {foo: "bar"}];
x[3]; // {foo: "bar"}
let z = [[1,2,3], [4,5,6]];
x[1]; // [4,5,6]
x[1][2]; // 6
let x = [1, 2, 3];
x[0] = 42;
x; // [42, 2, 3]
let x = [1, 2, 3];
x.length; // 3
let digits = [1, 2, 3];
for(let i = 0; i < digits.length; i++) {
// digits[i];
}
for(let digit of digits) {
// digit;
}
digits.forEach(digit => {
// digit;
});
let x = [12, 3, 1, 150];
x.push(17); // Ajoute 17 en fin de tableau
x; // [12, 3, 1, 150, 17]
x.pop(); // 17 - Supprime et retourne le dernier élement
x; // [12, 3, 1, 150]
x.unshift(42); // Ajoute 17 en début de tableau
x; // [42, 12, 3, 1, 150]
x.shift(); // 42 - Supprime et retourne le premier élement
x; // [12, 3, 1, 150]
x.splice(1, 2); // [12, 150] - Supprime 2 éléments à la position 1
let x = [12, 3, 1, 150];
x.map(element => element * 2); // [24, 6, 2, 300]
x.reduce((acc, element) => acc + element) // 166
x.sort();
x; // [1, 12, 150, 3]
x.sort((a, b) => a - b);
x; // [1, 3, 12, 150]
x.reverse()
x; // [150, 12, 3, 1]
let x = [12, 3, 1, 150];
x.indexOf(3); // 1 - Trouve l'index d'un élément
x.includes(3); // true - Indique la présence d'un élément
x.find(element => element === 3); // 3 - Trouve un élément
x.find(element => element === 0); // undefined
x.findIndex(element => element === 3); // 1 - Trouve l'index d'un élément
x.findIndex(element => element === 0); // -1
x.filter(element => element < 10); // [3, 1] - Filtre les éléments
// Object vide
let x = {};
let y = new Object();
let z = {
firstname: "John",
"lastname": "Doe",
age: 24,
'engineer': true,
company: "slides.com"
};
let x = {
firstname: "John",
"lastname": "Doe",
age: 24,
'engineer': true,
company: "slides.com"
};
x.age; // 24
x['company']; // "slides.com"
let x = {
firstname: "John",
"lastname": "Doe",
age: 24,
'engineer': true,
company: "slides.com"
};
x.age = 20;
x['company'] = "IUT Lyon 1";
x['passion'] = "Piano";
x;
// {
// firstname: "John",
// lastname: "Doe",
// age: 20,
// engineer: true,
// company: "IUT Lyon 1"
// passion: "Piano"
// }
let x = {
firstname: "John",
company: {
name: "Google",
address: "California"
}
};
x.company.name; // "Google"
x.home; // undefined
x.home.address; // Uncaught TypeError: x.home is undefined
let x = {
firstname: "John",
company: {
name: "Google",
address: "California"
}
};
x.company.name; // "Google"
x?.home; // undefined
x?.home?.address; // undefined
in
let x = {
firstname: "John",
company: {
name: "Google",
address: "California"
}
};
'company' in x; // true
'home' in x; // false
let x = {
firstname: "John",
company: {
name: "Google",
address: "California"
}
};
delete x.company;
x; // {firstname: "John"}
let x = {
firstname: "John",
company: {
name: "Google",
address: "California"
}
};
Object.keys(x); // ["firstname", "company"]
Object.keys(x.company); // ["name", "address"]
let x = {
firstname: "John",
company: {
name: "Google",
address: "California"
}
};
// Historique
for(let property in x) {
// x[property];
}
// Performance
Object.keys(x).forEach(property => {
// x[property];
})
Object.entries(x).forEach((key, value) => {
// value;
})
const firstname = "John";
const lastname = "Doe";
const company = {
name: "Google",
address: "California"
};
let x = {
firstname,
lastname,
company
};
x;
// {
// firstname: "John",
// lastname: "Doe",
// company: {
// name: "Google",
// address: "California"
// }
// }
const firstname = "John";
const company = {
name: "Google",
address: "California"
};
let x = {
firstname,
...company
};
x;
// {
// firstname: "John",
// name: "Google",
// address: "California"
// }
Oui
Non
Oui
Non
foo = ["x", "y", "z"]
, foo[2]
retournex
y
z
Une erreur
foo = ["x", "y", "z"]
, foo[2]
retournex
y
z
Une erreur
foo.size
foo.length
foo.lenght
foo.dimensions
foo.size
foo.length
foo.lenght
foo.dimensions
Que mon code est plus performant
Que monde code n'a pas de bug
Que certains navigateurs ne supportent pas mon code
Que mon code est plus joli
Que mon code est plus performant
Que mon code n'a pas de bug
Que certains navigateurs ne supportent pas mon code
Que mon code est plus joli
foo.push(1337)
foo[] = 1337
foo.add(1337)
foo += 1337
foo.push(1337)
foo[] = 1337
foo.add(1337)
foo += 1337
for(let element of elements) {...}
elements.forEach(element => {...})
for(const element of elements) {...}
loop(elements) {...}
for(let element of elements) {...}
elements.forEach(element => {...})
for(const element of elements) {...}
loop(elements) {...}
Array.forEach
Array.map
Array.reduce
Array.sort
Array.forEach
Array.map
Array.reduce
Array.sort
doivent être écrites en "double quote"
peuvent être écrites en "double quote"
peuvent être écrites en `back quote`
peuvent être écrites sans être entourées
doivent être écrites en "double quote"
peuvent être écrites en "double quote"
peuvent être écrites en `back quote`
peuvent être écrites sans être entourées
Vrai
Faux
Vrai
Faux
infos.company.name
infos['company'].name
infos.name
Beaucoup de travail
let infos = {
firstname: "John",
company: {
name: "Google",
address: "California"
}
};
infos.company.name
infos['company'].name
infos.name
Beaucoup de travail
let infos = {
firstname: "John",
company: {
name: "Google",
address: "California"
}
};
foo.bar
?Une erreur
undefined
null
foo
let foo = {};
foo.bar; // ?
foo.bar
?Une erreur
undefined
null
foo
let foo = {};
foo.bar; // ?
foo.bar.qux
?Une erreur
undefined
null
foo
let foo = {};
foo.bar.qux; // ?
foo.bar.qux
?Une erreur
undefined
null
foo
let foo = {};
foo.bar.qux; // ?
bar
existe ou non dans l'objet foo
via...'bar' in foo
Object.keys
et Array.indexOf()
l'opérateur instanceof
le chainage optionnel
(?.
)
et l'operateur ===
bar
existe ou non dans l'objet foo
via...'bar' in foo
Object.keys
et Array.indexOf()
l'opérateur instanceof
le chainage optionnel
(?.
)
et l'operateur !
==
data
?Réponse A
Réponse B
Réponse C
Réponse D
let width = 67
let height = 23
let measures =
{ width, height }
let color = "red"
let texture = "vinyle"
let data = {
color,
texture: "iron",
...measures
}
{ // Réponse A
color: "red",
texture: "vinyle",
measures: {
width: 67,
height: 23
}
}
{ // Réponse C
color: "red",
texture: "iron",
width: 67,
height: 23
}
{ // Réponse B
color: undefined,
texture: "iron",
width: 67,
height: 23
}
{ // Réponse D
color: "red",
texture: "iron",
measures: {
width: 67,
heigth: 23
}
}
data
?Réponse A
Réponse B
Réponse C
Réponse D
let width = 67
let height = 23
let measures =
{ width, height }
let color = "red"
let texture = "vinyle"
let data = {
color,
texture: "iron",
...measures
}
{ // Réponse A
color: "red",
texture: "vinyle",
measures: {
width: 67,
height: 23
}
}
{ // Réponse C
color: "red",
texture: "iron",
width: 67,
height: 23
}
{ // Réponse B
color: undefined,
texture: "iron",
width: 67,
height: 23
}
{ // Réponse D
color: "red",
texture: "iron",
measures: {
width: 67,
heigth: 23
}
}
data
?Réponse A
Réponse B
Réponse C
Réponse D
let width = 67
let height = 23
let weight = 19
let measures =
{width, height, weight}
let data = {
weight: 42,
texture: "iron",
...measures
}
{ // Réponse A
texture: "iron",
weight: 42,
measures: {
width: 67,
height: 23,
weight: 19,
}
}
{ // Réponse C
weight: 19,
texture: "iron",
width: 67,
height: 23,
}
{ // Réponse B
texture: "iron",
width: 67,
height: 23,
weight: 19,
}
{ // Réponse D
texture: "iron",
measures: {
width: 67,
heigth: 23,
weight: 19,
},
}
data
?Réponse A
Réponse B
Réponse C
Réponse D
let width = 67
let height = 23
let weight = 19
let measures =
{width, height, weight}
let data = {
weight: 42,
texture: "iron",
...measures
}
{ // Réponse A
texture: "iron",
weight: 42,
measures: {
width: 67,
height: 23,
weight: 19,
}
}
{ // Réponse C
weight: 42,
texture: "iron",
width: 67,
height: 23,
}
{ // Réponse B
texture: "iron",
width: 67,
height: 23,
weight: 19,
}
{ // Réponse D
texture: "iron",
measures: {
width: 67,
heigth: 23,
weight: 19,
},
}
let x = new Set();
x.add(42); // { 42 }
x.add("foo"); // { 42, "foo" }
x.has("foo"); // true
x.has(1337); // false
x.delete("foo");
x.size; // 1
for (let item of x) {
// items;
}
let x = new Map();
x.set(42, "quarante-deux'");
x.set("foo", "f o o");
x.size; // 2
x.get(42); // "quarante-deux";
x.get("foo") // "f o o"
x.delete("foo");
x.forEach((value, key) => {
// value;, key;
});
let a = new Date() // Maintenant
let b = new Date(1537621200000) // Milisecondes depuis l'epoch Unix
let c = new Date('2018-09-22T15:00:00+02:00') // Format ISO 8601
let d = new Date(2018, 8, 22) // Le mois est 0-indexé
ISO 8601
let x = new Date('2018-09-22T15:00:00+02:00')
x.getTime(); // 1537621200000
x.toLocaleDateString(); // "2018-9-22"
x.toLocaleTimeString(); // "15:00:00"
x.toISOString(); // "2018-09-22T13:00:00.000Z"
ISO 8601
let x = new Date('2018-09-22T15:00:00+02:00');
x.getDate(); // 22
x.setDate(30); // Date { 2018-09-30T13:00:00.000Z }
// Je vous épargne tout les getters/setters
let now = new Date().getTime();
let now = Date.now();
JSON est une syntaxe pour sérialiser des objets, tableaux, nombres, chaînes de caractères, booléens et valeurs null.
Elle est basée sur la syntaxe de JavaScript mais en est distincte : du code JavaScript n’est pas nécessairement du JSON, et du JSON n’est pas nécessairement du JavaScript.
{
firstname: "John",
'lastname': 'Doe',
"age": 024,
"company": {
`hiring`: true,
"nextWebTalent": undefined
},
"examDate": null,
"courses": ['JavaScript', "Vue.js"],
}
{
firstname: "John",
'lastname': 'Doe',
"age": 024,
"company": {
`hiring`: true,
"nextWebTalent": undefined
},
"examDate": null,
"courses": ['JavaScript', "Vue.js"],
}
{
firstname: "John",
"lastname": "Doe",
"age": 24,
"company": {
"hiring": true
},
"examDate": null,
"courses": ["JavaScript", "Vue.js"]
}
let decoded = { firstname: 'John', age: 24, company: "Google" };
JSON.stringify(decoded);
// '{"firstname":"John","age":24,"company":"Google"}'
let encoded = '{"firstname":"John","age":24,"company":"Google"}';
JSON.parse(encoded);
// {
// firstname: 'John',
// age: 24,
// company: 'Google'
// }
function maFonctionInutile() {
}
maFonctionInutile(); // undefined
function addition(a, b, c = 0) {
return a + b + c;
}
addition(40, 2); // 42
addition(40, 2, 1); // 43
const addition = function (a, b, c = 0) {
return a + b + c;
}
addition(40, 2); // 42
addition(40, 2, 1); // 43
const addition = (a, b, c = 0) => {
return a + b + c;
}
addition(40, 2); // 42
addition(40, 2, 1); // 43
const majuscule = str => str.toUpperCase();
majuscule("hello world"); // "HELLO WORLD"
const casting = (a, b, ...plusEncore) => {
let liste = `${a} et ${b}`;
if(plusEncore.length > 0) {
liste += ` (et ${plusEncore.join(", ")})`;
}
return liste;
};
casting("Alice", "Bob");
// "Alice et Bob"
casting("Alice", "Bob", "Charlie", "Dan");
// "Alice et Bob (et Charlie, Dan)"
function exclamer(str) {
str += " !";
return str;
}
// Type primitif
let x = "Hello world";
exclamer(x); // "Hello world !"
x; // "Hello world"
x = exclamer(x);
x; // "Hello world !"
!!!
function exclamer(obj) {
obj.y += " !";
}
// Type objet
let x = {};
x.y = "Hello world";
exclamer(x);
x.y; // "Hello world !"
Type primitif passé par copie
Type objet passé par référence
Oui
Non
Oui
Non
D'une chaine au format ISO 8601
D'un timestamps UNIX en seconde
De rien
D'une chaine formater au format Français
D'une chaine au format ISO 8601
D'un timestamps UNIX en seconde
De rien
D'une chaine formater au format Français
est un format de donnée standardisé
n'est pas JavaScript
est un format de donnée standardisé
n'est pas JavaScript
JSON.encode()
JSON.serialize()
JSON.stringify()
new JSON()
JSON.encode()
JSON.serialize()
JSON.stringify()
new JSON()
peut avoir des arguments par défaut
peut s'appeler elle même
peut être stockée dans une variable
retourne null si rien n'est retourné via le mot clé return
peut avoir des arguments par défaut
peut s'appeler elle même
peut être stockée dans une variable
retourne null si rien n'est retourné via le mot clé return
...
) dans une fonction permetD'ignorer les paramètres
Récupérer les paramètres dynamiquement
...
) dans une fonction permetD'ignorer les paramètres
Récupérer les paramètres dynamiquement
number
serait passé par copieVrai
Faux
Cela dépend
number
serait passé par copieVrai
Faux
Cela dépend
Date
serait passer par copieVrai
Faux
Cela dépend
Date
serait passer par copieVrai
Faux
Cela dépend
try catch
try {
vivreTranquille();
} catch (e) {
if(e.message === "exam") {
reviser();
}
}
function vivreTranquile() {
// ...
throw new Error("exam");
// ...
}
-
-
-
File
d'événements
Gére l'exécution asynchrone des événements
document.body.addEventListener('click', () => {
alert("Hello world");
})
console.log("Le petit oiseau va sortir dans 2 secondes !")
setTimeout(() => {
console.log("Coucou !");
}, 2000);
let compteur = 10;
setInterval(() => {
if(compteur === 0) {
console.log("BOOM !")
}
else if(compteur > 0) {
console.log(compteur);
}
compteur--;
}, 1000);
En attente
Résolue
Rejetée
En attente
Résolue
Rejetée
Résultat à l'exam
Exam passé
Exam échoué
const promise = new Promise((resolve, reject) => {
let examResult = undefined;
while(examResult === undefined) {
examResult = resultAreOut();
}
if(examResult) {
resolve(getExamGrade());
} else {
reject(getExamRetryDate());
}
})
promise.then((grade) => {
if(grade > 15) {
console.log('Very nice !');
} else {
console.log('Nice...');
}
}).catch((retryDate) => {
console.log('Retry exam date', retryDate);
})
const promise = new Promise((resolve, reject) => {
let examResult = undefined;
while(examResult === undefined) {
examResult = resultAreOut();
}
if(examResult) {
resolve(getExamGrade());
} else {
reject(getExamRetryDate());
}
})
async function () {
try {
let grade = await promise;
//...
} catch(retryDate) {
retryDate;
//...
}
}
let maVariable = 42;
console.log(maVariable);
// > 42
console.log({maVariable});
// > { maVariable: 42 }
//
console.info("foo");
console.warn("bar");
console.error("qux");
// Effacer la console
console.clear();
// Afficher la pile d'appel
console.trace();
// Mesurer le temps
console.time("mesurer durée traitement");
console.timeEnd("mesurer durée traitement");
debugger;
// module.js
export default {
name: "John"
};
export const email = "jhon@doe.pro";
let website = "doe.pro";
export website;
// main.js
import Module from "./module.js";
Module; // { name: "John" }
import { email } from "./module.js";
email; // "john@doe.pro"
import { website as url } from "./module.js";
url; // "doe.pro"
// Une seul ligne
import Module, { email, website as url } from "./module.js";
Sauf bug du moteur Javascript, c'est vrai
Faux
Ca dépend
Sauf bug du moteur Javascript, c'est vrai
Faux
Ca dépend
Faux
Vrai
Faux
Vrai
peuvent ne jamais être résolu
ont un nombre infini d'états possibles
ont 3 états possibles
ont 4 états possibles
peuvent ne jamais être résolu
ont un nombre infini d'états possibles
ont 3 états possibles
ont 4 états possibles
await
permet de bloquer un contexte d’exécution en attendant la fin d'une promesse
Faux
Vrai
await
permet de bloquer un contexte d’exécution en attendant la fin d'une promesseFaux
Vrai
export 42;
export default 42;
export const x = 42;
export { 42 }
export 42;
export default 42;
export const x = 42;
export { 42 }
export "foo";
export default "foo";
export const y = "foo";
export {y: "foo"}
export "foo";
export default "foo";
export const y = "foo";
export {y: "foo"}
Représente la page web sous forme d'arbre de nœuds
Chaque nœud représente un élément HTML, un attribut, du texte ou un commentaire
Manipulable (ajout, modification, suppression) par une API
Utilisé pour créer des applications web interactives et dynamiques.
Standard du World Wide Web Consortium (W3C) / JS
<!doctype html>
<html lang="fr">
<head>
<meta charset="utf-8">
<title>Apprenons JS</title>
<script src="script.js"></script>
</head>
<body>
<h1>Hello world</h1>
<input id="titre" type="text" />
<button>Envoyer</button>
</body>
</html>
document.body;
// <body>
document.getElementById("titre");
// <input id="titre">
document.querySelectorAll("*");
// [<html>, <head>, ...]
window.title;
// "Apprenons JS"
<!doctype html>
<html lang="fr">
<head>
<meta charset="utf-8">
<title>Apprenons JS</title>
<script src="script.js"></script>
</head>
<body>
<h1>Hello world</h1>
<input id="titre" type="text" />
<button>Envoyer</button>
</body>
</html>
let input = document.querySelector("#titre");
// Valeur du champ
input.value;
input.getAttribute("type"); // "text"
input.setAttribute("type", "password");
<!doctype html>
<html lang="fr">
<head>
<meta charset="utf-8">
<title>Apprenons JS</title>
<script src="script.js"></script>
</head>
<body>
<p>Hello<br />world</p>
<input id="titre" type="text" />
<button>Envoyer</button>
</body>
</html>
let paragraph = document.querySelector("p");
paragraph.textContent;
// "Hello world"
paragraph.innerHTML;
// "Hello<br />world"
paragraph.outerHTML;
// "<p>Hello<br />world</p>"
<!doctype html>
<html lang="fr">
<head>
<meta charset="utf-8">
<title>Apprenons JS</title>
<script src="script.js"></script>
</head>
<body>
<h1 class="head">
Hello world
</h1>
<input id="titre" type="text" />
<button>Envoyer</button>
</body>
</html>
let header = document.querySelector("h1");
header.classList.contains('head');
// true
header.classList.add('strong');
header.classList.remove('head')
<!doctype html>
<html lang="fr">
<head>
<meta charset="utf-8">
<title>Apprenons JS</title>
<script src="script.js"></script>
</head>
<body>
<h1>Hello<br />world</h1>
<input id="titre" type="text" />
<button>Envoyer</button>
</body>
</html>
let bouton = document.querySelector("button");
bouton.addEventListener("click", () => {
alert("Clicked !");
});
// Il y a de nombreux événements écoutables
//
// mousedown, mouseup, mousemove, click, dblclick
// keydown, keyup, keypress
// scroll
// ...
<!doctype html>
<html lang="fr">
<head>
<meta charset="utf-8">
<title>Apprenons JS</title>
<script src="script.js"></script>
</head>
<body>
<h1 class="head">
Hello world
</h1>
<input id="titre" type="text" />
<button>Envoyer</button>
</body>
</html>
let img = document.createElement("IMG");
document.body.appendChild(img);
https://glitch.com/edit/#!/iut-todo-list-js
<body>
<ul></ul>
<input type="text" />
<button>Ajouter</button>
</body>
let ul = document.querySelector("ul");
let input = document.querySelector("input");
let button = document.querySelector("button");
button.onclick = () => {
let item_li = document.createElement("LI");
let item_span = document.createElement("SPAN");
item_span.textContent = input.value;
item_li.appendChild(item_span);
let item_button = document.createElement("BUTTON");
item_button.textContent = "X";
item_button.onclick = () => {
item_span.style.textDecoration = "line-through";
};
item_li.appendChild(item_button);
ul.appendChild(item_li);
input.value = "";
};
Modèle de données
Couplé fortement à la vue
Non centralisé
Non écoutable
Vue
Vue
Logique
Modèle
Modifie
Actualise
Appel
// View
let ul = document.querySelector("ul")
let input = document.querySelector("input")
let button = document.querySelector("button")
function render() {
ul.innerHTML = ""
input.onkeyup = () => updateNewLabel(input.value)
for (let todo of todos) {
let item_li = document.createElement("LI")
let item_span = document.createElement("SPAN")
item_span.textContent = todo.label;
item_span.style.textDecoration = todo.done
? "line-through" : ""
item_li.appendChild(item_span)
let item_button = document.createElement("BUTTON")
item_button.textContent = "X"
item_button.onclick = () => removeTodo(todo);
item_li.appendChild(item_button)
ul.appendChild(item_li)
}
input.value = newLabel
button.onclick = () => addTodo()
}
<body>
<ul></ul>
<input type="text" />
<button>Ajouter</button>
</body>
// Model
let todos = []
let newLabel = ""
// Actions
function addTodo() {
todos.push({
label: newLabel,
done: false
});
newLabel = ""
render()
}
function removeTodo(todo) {
todo.done = true
render()
}
function updateNewLabel(_newLabel) {
newLabel = _newLabel
render()
}
Utilisateur
Frontend
Backend
Database
</>
https://dayssincelastjavascriptframework.com/
Framework JavaScript pour le développement d'application web
Simplifie le développement d'interface dynamique
Populaire : Adobe, GitLab, ...
Juil 2013 - Premier commit par Evan You (@Google Creative Lab)
Fév 2014 - Version 0.9 - Première annonce publique
Oct 2015 - Version 1.0
Sep 2016 - Version 2.0
Fév 2022 - Version 3.0
Réelle plus value
Puissant
Léger
Open source
Populaire
Communauté active
Maintenu
Bien documenté
Permet de séparer la vue, le modèle de données et la logique applicative
Vue
Logique
Modèle
Modifie
Actualise
Appel
Vue
?
Modèle
Modifie
?
?
npm init vue@latest
// Version de développement
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
// Version de production
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
// Plus usuellement
import { createApp } from "vue"
<div id="app"></div>
import { createApp } from 'vue'
import App from './App.vue'
const app = createApp(App)
app.mount("#app")
<script setup>
import { ref } from 'vue'
const message = ref("Hello world")
</script>
<template>
<h1>{{ message }}</h1>
</template>
<style scoped>
h1 {
text-decoration: underline;
}
</style>
DiscoverHelloWorld
Mise à jour automatique de l'UI et des données en fonction des mutations dans les données
Basé sur le design pattern Observer
Développement plus simple
et efficace
<script setup>
import { ref } from 'vue'
const message = ref("Hello world")
</script>
<template>
<h1>{{ message }}</h1>
</template>
DiscoverReactivity
<script setup>
import { ref } from 'vue'
const url = ref("learn.png")
setTimeout(() => {
url.value = "master.png"
}, 5000)
</script>
<template>
<img :src="url" />
</template>
DiscoverTemplate
<script setup>
import { ref } from "vue"
const speed = ref(10)
</script>
<template>
<p v-if="speed < 88">
Plus vite Doc !
</p>
<p v-else-if="speed === 88">
88 mph !
</p>
<p v-else>Retour vers le futur !</p>
<pre>
En console, entrer :
window.speed.value = 100
</pre>
</template>
DiscoverCondition
<script setup>
import { ref } from "vue"
const verbs = ref([
{ id: 0, text: "Veni" },
{ id: 1, text: "Vidi" }
{ id: 2, text: "Vici" }
])
</script>
<template>
<ul>
<li
v-for="verb in verbs"
:key="verb.id"
>
{{ verb.text }}
</li>
</ul>
</template>
DiscoverLoop
<script setup>
import { ref } from "vue"
const verbs = ref([
{ id: 0, text: "Veni" },
{ id: 1, text: "Vidi" }
{ id: 2, text: "Vici" }
])
</script>
<template>
<ul>
<li
v-for="(verb, index) in verbs"
:key="verb.id"
>
#{{ index }} {{ verb.text }}
</li>
</ul>
</template>
DiscoverVForIndexed
<script setup>
import { ref } from "vue"
const count = ref(0)
function increment() {
count.value++
}
</script>
<template>
<p>{{ count }}</p>
<button @click="increment">
Incrémenter !
</button>
</template>
DiscoverEvent
<script setup>
import { ref } from "vue"
const count = ref(0)
function increment(delta) {
count.value += delta
}
</script>
<template>
<p>{{ count }}</p>
<button @click="increment(3)">
Incrémenter !
</button>
</template>
DiscoverEventHandlerWithParameters
<script setup>
import { ref } from "vue"
const input = ref("Hello !")
</script>
<template>
<input v-model="input" />
<p>{{ input }}</p>
<button @click="input = 'Hello !'">
Reset
</button>
</template>
DiscoverVmodel
<script setup>
import { ref } from "vue"
const size = ref(10)
</script>
<template>
<button @click="size = 10">Small</button>
<button @click="size = 20">Medium</button>
<button @click="size = 30">Large</button>
<h1 :style="{fontSize: size + 'px'}">
Hello world
</h1>
</template>
DiscoverStyle
<script setup>
import { ref } from "vue"
const isRed = ref(true)
</script>
<template>
<h1 class="text"
:class="{highlight: isRed}"
>
Hello world
</h1>
<button @click="isRed = !isRed">
Toggle
</button>
</template>
<style scoped>
.highlight { color: red; }
.text { font-style: italic; }
</style>
DiscoverClass
// LightSaber.vue
<script setup>
</script>
<template>
<span>Yoda</span>
<span class="handle">|||||</span>
<span class="light">======</span>
</template>
<style scoped>
.handle {
display: inline-block;
background: grey;
}
.light {
display: inline-block;
background: lightgreen;
color: transparent;
}
</style>
<script setup>
import LightSaber from "./LightSaber.vue"
</script>
<template>
<LightSaber />
</template>
DiscoverComponent
// LightSaber.vue
<script setup>
const props = defineProps({
owner: String,
color: String
})
</script>
<template>
<div>
<span>{{ owner }}</span>
<span class="handle">|||||</span>
<span class="light"
:style="{background: color}">
======
</span>
</div>
</template>
<style scoped>...</style>
<script setup>
import LightSaber from "./LightSaber.vue"
</script>
<template>
<LightSaber owner="Mace windu" color="magenta" />
</template>
DiscoverProp
<script setup>
import LightSaber from "./LightSaber.vue"
const jedis = ref([
{ name: 'Obi-Wan', color: 'lightblue' },
{ name: 'Darth Vader', color: 'red' },
{ name: 'Rey', color: 'orange' },
])
</script>
<template>
<LightSaber
v-for="jedi in jedis"
:owner="jedi.name"
:key="jedi.name"
:color="jedi.color"
/>
</template>
DiscoverPropLoop
<div>
{{ message.split('').reverse().join('') }} <!-- #1 Sémantique difficile -->
</div>
...
<div>
{{ message.split('').reverse().join('') }} <!-- #2 Performance dégradée -->
</div>
...
<div>
{{ message.split('').reverse().join('') }} <!-- #3 Répétition évitable -->
</div>
<script setup>
import { ref, computed } from "vue"
const message = ref("Hello world")
const reversed = computed(() =>
message.value
.split('')
.reverse()
.join('')
)
// Une computed est une référence calculée à partir d'une expression
// Elle se met à jour automatiquement de façon réactive
// C'est une sorte de référence en lecture seule
</script>
<template>
<p>Message original : {{ message }}</p>
<p>Message inversé : {{ reversed }}</p>
</template>
DiscoverComputed
<script setup>
// ...
const reverse = () =>
message.value
.split('')
.reverse()
.join('')
</script>
<template>
Message inversé : {{ reverse() }}
</template>
const now = computed(() =>
Date.now()
)
// Une computed n'est recalculée que sur des références réactives
Différence : computed met en cache son résultat alors qu'une fonction est executé à chaque rendu de la vue
<script setup>
import { ref, computed } from "vue"
const numbers = ref([1, 2, 3, 4, 5])
const even = computed(() => {
return numbers.value.filter(
n => n%2 === 0
)
}) // [2, 4]
</script>
<template>
<li v-for="n in even">{{ n }}</li>
</template>
DiscoverListFiltering
<script setup>
import { ref } from "vue"
let letters = ref(
["J", "X", "O", "B", "U", "I"]
)
let sort = () => letters.value.sort()
</script>
<template>
<div @click="sort">
{{ letters }}
</div>
</template>
Méthodes de mutations réactives
push(), pop(), shift(), unshift(),
splice(), sort(), reverse()
DiscoverListMutation
1) Réimplementer la todo list
2) Ajouter un champ pour filtrer la liste des tâches par label.
3) Ajouter un select pour filtrer la liste des tâches par status
components/TodoList.vue
function getHelloWorld() {
const promise = fetch('https://www.xul.fr/ajax/ajax-get.json')
promise.then(res => res.json()) // { message: "Hello World !" }
}
// On préférera utiliser la syntaxe async/await
async function getHelloWorld() {
const res = await fetch('https://www.xul.fr/ajax/ajax-get.json')
const obj = await res.json() // { message : "Hello World !" }
}
async function getSomething() {
const res = await fetch('https://dummyjson.com/products/3')
// res.text()
// res.json()
// res.blob()
// res.arrayBuffer()
// res.formData()
}
async function getProducts() {
const res = await fetch('https://dummyjson.com/products/', {
headers: {
Authorization: `Token MY_API_KEY`,
Accept: 'application/json',
},
})
return await res.json()
}
async function putProduct() {
const res = await fetch('https://dummyjson.com/products/', {
method: 'PUT',
headers: {
Content-Type: 'application/json',
},
body: JSON.stringify({ name: 'Foo', description: 'Lorem ipsum' })
})
return await res.json()
}
async function getNotFound() {
const res = await fetch('https://www.jack-ceparou.com/olydri')
// res.status // 404
// res.statusText // "Not Found"
}
async function getDocumentations() {
const res = await fetch('https://developer.mozilla.org')
res.headers.get("Content-type") // "text/html; charset=utf-8"
for(let [header, value] of res.headers.entries()) {
console.log(header, value)
}
}
async function getDocumentations() {
try {
const res = await fetch(`http://somewhere.com/somewhat`)
if (!response.ok) {
throw new Error('Fail during fetching somewhat');
}
return await response.json();
} catch (error) {
console.error(error);
}
}
Specs README : https://github.com/Antloup/todo-list-server
1) Récupérer toutes les tâches
2) Permettre de filtrer par owner (computed)
3) Pouvoir enregistrer une nouvelle tâche dans le backend
4) Pouvoir passer à done une tâche
Application Programming Interface
Fourni un accès structuré à une application ou un service
Basé sur un protocole (ex: HTTP, TCP, ...) et un standard (ex: XML, JSON, ...) de communication
Architectures populaires : REST, SOAP
Representational State Transfer
Architecture logicielle pour système distribué largement utilisé pour les API web
Basé sur HTTP pour effectuer des opérations CRUD (Create, Read, Update, Delete) via les méthodes/verbes HTTP POST, GET, PUT ou PATCH, DELETE sur des ressources
Données au format JSON ou plus rarement XML
Framework back-end open-source pour Node.js.
Fonctionnalités : routage, gestion des requêtes et des réponses HTTP, authentification et bien plus encore.
Adapté pour la création d'API
npm install express
import express from 'express'
const app = express()
app.listen(3000, () => {
console.log('Server is listening on port 3000 !')
})
import express from 'express'
const app = express()
app.get('/', (req, res) => {
res.send('Hello world !');
})
app.listen(3000, () => {
console.log('Server is listening on port 3000 !')
})
app.get('/', (req, res) => {
res.send('GET at root');
})
app.post('/', (req, res) => {
res.send('POST at root');
})
app.put('/', (req, res) => {
res.send('PUT at root');
})
app.delete('/', (req, res) => {
res.send('DELETE at root');
})
app.get('/', (req, res) => {
res.send('GET at root');
})
app.get('/foo', (req, res) => {
res.send('GET at /foo');
})
app.get('/asHTML', (req, res) => {
res.send('GET at root'); // Content-Type : text/html
})
app.get('/asJSON', (req, res) => {
res.send({ foo: 'bar' }); // Content-Type : application/json
})
app.get('/asBinary', (req, res) => {
res.send(Buffer.from('baz')); // Content-Type : application/octet-stream
})
app.get('/fromFile', (req, res) => {
res.sendFile('/path/to/image.png');
})
app.get('/notFound', (req, res) => {
res.status(404)
res.end()
})
app.get('/headers', (req, res) => {
res.set('Access-Control-Allow-Origin', '*')
res.set({
'Content-Type': 'text/plain',
'Content-Length': '123',
'ETag': '12345'
})
res.end()
})
app.get('/redirection', (req, res) => {
res.redirect('/foo/bar')
// res.redirect('http://example.com')
// res.redirect(301, 'http://example.com')
// res.redirect('../login')
})
app.use(express.static('public'))
// http://localhost:3000/js/app.js
// http://localhost:3000/images/bg.png
// http://localhost:3000/hello.html
app.use('/static', express.static('public'))
// http://localhost:3000/static/js/app.js
// http://localhost:3000/static/images/bg.png
// http://localhost:3000/static/hello.html
app.get('/', (req, res) => {
res.send('Hello World!')
})
app.use((req, res, next) => {
console.log(`Request received at ${new Date()}`)
next() // Call the next middleware function
})
app.use((req, res, next) => {
res.setHeader('X-Custom-Header', 'Hello World')
next() // Call the next middleware function
})
const authMiddleware = (req, res, next) => {
const token = req.headers.authorization.split(' ')[1]
if(verifyToken(token)) {
next() // Call the next middleware function
} else {
res.status(401).json({ error: "Not authorized" })
}
}
app.get('/accounts', authMiddleware, (req, res) => {
res.send('Safe Hello World!')
})
import express from 'express'
const app = express()
app.use(express.json())
app.post('/users', (req, res) => {
const { name, email } = req.body
res.send(`User created: ${name} (${email})`)
})
import express from 'express'
import bodyParser from 'body-parser' // npm install body-parser
const app = express()
app.use(bodyParser.urlencoded({ extended: true }))
app.post('/login', (req, res) => {
const { username, password } = req.body
res.send(`Logged in as ${username}`)
})
<form method="POST" action="/login">
<input type="text" name="username" placeholder="Username">
<input type="password" name="password" placeholder="Password">
<button type="submit">Log In</button>
</form>
// http://localhost/search?q=Foo
app.get('/search', (req, res) => {
const { q } = req.query
res.send(`Search query is: ${q}`) // Search query is: Foo
})
// http://localhost/search?tag=Foo&tag=Bar
app.get('/search', (req, res) => {
const { tag } = req.query // Array if several given
res.send(`Tags are: ${tag}`) // Tags are: ['Foo', 'Bar']
})
app.get('/users/:userId', (req, res) => {
const { userId } = req.params
res.send(`User ID is: ${userId}`)
})
app.get('/users/:userId/posts/:postId', (req, res) => {
const { userId, postId } = req.params
res.send(`User ID is: ${userId}, Post ID is: ${postId}`)
})
npm i sequelize sqlite3
const sequelize = new Sequelize('sqlite::memory:')
import { DataTypes } from 'sequelize'
const User = sequelize.define('User', {
id: {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4,
allowNull: false,
primaryKey: true
},
username: {
type: DataTypes.STRING,
allowNull: false,
unique: true
},
age: {
type: DataTypes.DECIMAL,
allowNull: false
},
})
import { Op } from "sequelize"
// Create
await User.create({ username: "john", age: 42 }) // instance
// Read
const userById = await User.findByPk("de262606-070c-42e1-a43d-75c9696e919a") // instance | null
const userByName = await User.findOne({ where: { username: "alice" }) // instance | null
const users = await User.findAll({ where: { age: { [Op.gt]: 18 } } }) // array<instance>
// Update
await userByName.update({ age: 43 }) // instance
// Delete
await User.destroy({ where: { id: "de262606-070c-42e1-a43d-75c9696e919a" } }) // number
userById.destroy() // void
const User = sequelize.define('User', {
id: {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4,
allowNull: false,
primaryKey: true
},
email: {
type: DataTypes.STRING,
allowNull: false,
unique: true,
validate: {
isEmail: true
}
},
password: {
type: DataTypes.STRING,
allowNull: false,
validate: {
len: [8, 20]
}
}
})
try {
User.create({
email: 'user@example.com',
password: 'password'
})
} catch(e) {
// e.errors
// e.errors.map(error => error.message)
}
import { DataTypes } from 'sequelize'
const Task = sequelize.define('Task', {
id: {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4,
allowNull: false,
primaryKey: true
},
text: {
type: DataTypes.STRING,
allowNull: false
},
done: {
type: DataTypes.BOOLEAN,
allowNull: false
},
})
User.hasMany(Task, {
as: 'tasks',
foreignKey: 'userId',
onDelete: 'CASCADE'
})
Task.belongsTo(User, {
as: 'owner',
foreignKey: 'userId'
})
const user = await User.findOne({
attributes: ['id', 'username'],
include: [{
model: Task,
as: 'tasks',
attributes: ['label'],
where: { done: false }
}]
})
{
id: '1f2fadb1-0d7e-47a7-9d5b-5d3e',
username: 'casear',
tasks: [
{ label: 'Vini' },
{ label: 'Vidi' },
{ label: 'Vici' }
]
}
User.hasMany(Task, {
as: 'tasks',
foreignKey: 'userId',
onDelete: 'CASCADE'
})
Task.belongsTo(User, {
as: 'owner',
foreignKey: 'userId'
})
const user = await User.findOne({
attributes: ['username'],
include: [{
model: Collection,
as: 'collections',
include: [{
model: Task,
as: 'tasks',
attributes: ['label']
}]
}]
})
{
username: 'casear',
collections: [{
tasks: [
{ label: 'Vini' },
{ label: 'Vidi' },
{ label: 'Vici' }
]
}]
}
User.hasMany(Collection, {
as: 'collections',
foreignKey: 'userId',
onDelete: 'CASCADE'
})
Collection.belongsTo(User, {
as: 'owner',
foreignKey: 'userId'
})
Collection.hasMany(Task, {
as: 'tasks',
foreignKey: 'collectionId',
onDelete: 'CASCADE'
})
Task.belongsTo(Collection, {
as: 'collection',
foreignKey: 'collectionId'
})
Identification
Processus de reconnaissance d'un utilisateur ou d'une entité par le biais d'un nom d'utilisateur ou d'un identifiant unique.
Authentification
Processus de vérification de l'identité d'un utilisateur ou d'une entité.
Autorisation
Processus de détermination des droits d'accès d'un utilisateur ou d'une entité à des ressources spécifiques après qu'ils aient été identifiés et authentifiés.
Utilisateur
Authentification
Service d'authentification
Preuve (mot de passe, SMS, ...)
Token
Autorisation
Utilisateur
Service applicatif
Service d'authentification
Requête + Token
Token
Validation signature + droits
Réponse
Vérification
de non-révocation
Peut être
la même instance
Émission du jeton
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
{
"alg": "HS256",
"typ": "JWT"
}
{
"sub": "123456789",
"name": "John Doe",
"iat": 1516239022
}
Hash(Secret,
Header + Payload)
Header
Payload
Signature
import jwt from 'jsonwebtoken'
// Nous sommes libres sur le contenu du payload,
// mais il des pratiques normalisées
const data = {
jti: 'd6a0bf5d-bec1-4c85-852a-80cfd6ffbc74', // Numéro de série
exp: Math.floor(Date.now() / 1000) + (60 * 60), // Expire dans 1h
username: 'john.doe',
roles: ['ADMIN']
}
const token = jwt.sign(data, 'THE_SECRET')
import jwt from 'jsonwebtoken'
try {
const data = jwt.verify(token, 'THE_SECRET');
// Vérifier que data.exp n'a pas expiré
// Vérifier que data.roles est suffisant pour l'action en cours
// Vérifier que data.jti est un numéro de série non revoquée
} catch(e) {
// Erreur de vérification
}
{
"name": "mon-projet",
"version": "1.0.0",
"description": "Un exemple de projet avec NPM",
"main": "index.js",
"scripts": {
"start": "node index.js",
"clean": "rm -rf node_modules"
},
"author": "John doe",
"license": "MIT",
"dependencies": {
"express": "^4.17.1",
"lodash": "^4.17.21"
},
"devDependencies": {
"nodemon": "^2.0.12"
}
}
{
"name": "mon-projet",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"packages": {
"": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/mon-projet/-/mon-projet-1.0.0.tgz",
"integrity": "sha512-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"dependencies": {
"express": "^4.17.1"
}
},
"express": {
"version": "4.17.1",
"resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz",
"integrity": "sha512-mHJ9O79RqluphRrccoy1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==",
"requires": {
"body-parser": "1.19.0",
...
}
}
}
}
# Créer un package.json originel pour votre projet
npm init
# Ajoute une dépendance au package.json et l'installe dans node_modules/
npm install lodash
# Idem pour une dépendance de développement
npm install typescript --save-dev
# Installe les node_modules à partir des dépendances du package.json
npm install
import lodash from "lodash"
// Old way
const lodash = require("lodash")
# Lance un script définit dans package.json
npm run start
Compile
JSDoc
Classes
Typing
Classes
Abstract classes
Interfaces
Generics
Decorators
Type inference
Inheritance
Inheritance
Enums
Type guards
Union types
Better auto-complete
/**
* @param {number} a
* @param {number} b
* @returns {number}
*/
function addition(a, b) {
return a + b;
}
function addition(a: number, b: number): number {
return a + b;
}
type InfosType = {firstname: string; company: {name: string; address: string}, age?: number}
let infos: InfosType = {
firstname: "John",
company: {
name: "Google",
address: "California"
},
};
/**
* @typedef {Object} InfosType
* @property {string} firstname
* @property {Object} company
* @property {string} company.name
* @property {string} company.address
* @property {number} [age]
*/
/** @type {InfosType} */
let infos = {
firstname: "John",
company: {
name: "Google",
address: "California"
},
};
function division(a: number, b: number) {
return b !== 0 ? a / b : 'wtf?';
}
const foo = division(1,2); // foo: number | 'wtf?'
const infos = {
firstname: "John",
company: {
name: "Google",
address: "California"
},
};
// infos: {firstname: string; company: {name: string; address: string}}
enum Direction {
Up,
Down,
Left,
Right
}
function movePlayer(direction: Direction) {
// ...
}
let oneDirection = Direction.Up; // oneDirection: Direction
movePlayer(oneDirection);
interface Animal {
name: string;
speak(): void;
}
abstract class AbstractAnimal implements Animal {
constructor(public name: string) {}
abstract speak(): void;
}
class Dog extends AbstractAnimal {
constructor(public name: string) {
super(name);
}
speak(): void {
console.log(`${this.name} says Woof!`);
}
}
type NonNullType<T> = Exclude<T, null | undefined>
function filterNonNull<T>(array: T[]) {
return array.filter((item): item is NonNullType<T> => item !== null && item !== undefined);
}
const foo = [undefined, 1, 2, null, null, 42, undefined]; // foo: (undefined | null | number)[]
const bar = filterNonNull(foo); // bar: number[]
function simpleDecorator(target: any, property: string, options: PropertyDescriptor) {
console.log("Decorating:", property);
}
class MyClass {
@simpleDecorator
greet() {
console.log("Hello!");
}
}
new MyClass().greet(); // Output: Decorating: greet\nHello!
<script setup lang="ts">
import { ref } from 'vue'
const message = ref("Hello world")
</script>
<template>
<h1>{{ message }}</h1>
</template>
<style scoped>
h1 {
text-decoration: underline;
}
</style>
Génération du rapport: cd frontend && npm run test-report
Interface Cypress: cd frontend && npm run test
Lancer sous Chrome: Vérifiez que aucun tests ne passe suite au clonage du projet
branch main
branch main-ts