Les tableaux (classe Array) font partie de la bibliothèque standard Javascript. On peut créer un tableau vide avec [].
let tab = [];
tab[35]; //undefined
tab[35] = "Hello"; //initialise la case 35 à "Hello"
tab[0]; //toujours undefined;
tab.length; //36 ! indice le plus grand ayant été
//initialisé + 1
let couleurs = [ "rouge", "bleu", "vert", "jaune", "violet" ];
//avant;
let c_rouge = couleurs[0];
let c_bleu = couleurs[1];
let c_vert = couleurs[2];
// maintenant
let [ c_rouge, c_bleau, c_vert ] = couleurs;
// autres cases ignorées
let [ c_rouge, c_bleau, c_vert, ...autres ] = couleurs;
// autres est un tableau à 2 cases [ "jaune", "violet" ]
En Javascript, on peut toujours appeller une fonction avec un nombre quelconque d'arguments.
Si la fonction est définie avec plus de paramètres, les paramètres manquant sont initialisé à undefined
Si la fonction est définie avec moins de paramètres, les arguments supplémentaires sont ignorés
On peut définir des fonctions variadiques:
function f (a, b, ...others) {// attentions, le ...
// fait partie de la syntaxe
console.log(others);
}
others est un tableau contenant les arguments en plus. Il ne peut y avoir qu'un seul argument ...x qui doit être le dernier paramètre.
On peut itérer sur une collection avec la construction for … of. Plusieurs objets de la bibliothèque standard implémentent la méthode .entries() qui renvoie la collection des entrées :
let tab = [ "A", "B", "C", "D" ];
for (let e of tab) {
console.log(e); // affiche "A" "B" "C" "D"
}
for (let e of tab.entries()) {
console.log(e); // affiche [0,"A"] [1,"B"] [2,"C"], [3,"D"]
}
for (let [i,e] of tab.entries()) { //avec un let destructurant
console.log(i, e); // affiche 0 "A" 1 "B" 2 "C" 3 "D"
}
Il est souvent utile de pouvoir échanger de l'information « structurée » entre applications
Solutions actuelles
Une valeur JSON est représenté par un sous-ensemble de la syntaxe Javascript pour les objets.
{ "nom" : "Nguyen",
"prénom" : "Kim",
"cours": [ "Javascript", "TER" ],
"full time" : true,
"age" : 3.6e1,
"hobby" : null }
L'objet JSON disponible en Javascript possède deux méthodes :
JSON.parse("1");
> 1
JSON.parse("[ 1, 2, \"3\", false ]");
> [1, 2, "3", false]
JSON.parse("null"); "\a"
> null
var o = JSON.parse("{ \"a\" : 1 }");
> undefined
o.a;
> 1
JSON.parse("{ a : 1 }");
> erreur
JSON.parse("{ ");
> erreur
JSON.parse("undefined");
> erreur
Beaucoup de règles :
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
this.f = function () {};
}
move (i, j) {
this.x += i;
this.y += j;
}
}
let p = new Point(1,2);
JSON.stringify(p);
> "{\"x\":1,\"y\":2}"
Les propriétés du prototype n'ont pas été énumérées, celle de l'objet qui est une fonction (f) a été ignorée
Une fois parsée, la valeur JSON devient une valeur Javascript (utilisation directe des propriétées)
Une valeur XML devient un objet DOM, dans lequel il faut naviguer avec .getFirstChild(), .getElementById(), ...
Par contre JSON ne possède pas de notion de schéma bien établie (draft en cours) donc il faut valider « à la main »
Une application Web doit parfois échanger avec un serveur Web :
Utilisation de formulaires HTML :
AJAX : API permettant d'envoyer des requêtes HTTP à un serveur depuis Javascript de manière asynchrone, en tâche de fond et de récupérer le résultat
Objet contenant les (nombreuses) méthodes permettant d'envoyer une requête GET ou POST à un serveur distant :
On se connecte à l'évennement readystatechange de l'objet XmlHttpRequest. Exemple:
Avantages :
Inconvénient
On peut demander un résultat d'un autre type que string (document HTML, objet JSON, …)
On souhaite faire une boite de texte qui propose de la complétion à partir d'un dictionaire en français.
On doit écrire une partie serveur et une partie client.
Ces notions sont distinctes et toutes présentes en Javascript
Le moteur d'exécution Javascript est mono-thread. Il
ne permet donc pas de
calculs parallèles. Si on effectue
un calcul coûteux (en temps), la page se « fige ». Les
navigateurs interdisent ce genre de comportements.
Deux implications sur le code Javascript :
On va explorer au travers d'exemple comment écrire du code respectant ces contraintes en « pur javascript simple™ »
(Le cours 6 montrera les nouveautés du standard ECMAScript 6 et 7 qui permettent de faire ça de manière élégante)
On veut modifier l'exemple précédant du dictionnaire pour appeler, pour chaque mot renvoyé, un deuxième service Web qui met ce mot en gras
//step 1 appelle une continuation en lui passant
//la valeur qu'elle calcule de manière asynchrone
step1 (function (value1) {
…
step2(function (value2) {
…
step3(function (value3) {
…
step4(function (value4) {
// on peut enfin faire quelque chose avec value4
}
}
}
}
Problèmes du code asynchrone
Solution : promesses (promises). Permettent de simuler du code séquentiel
let p = new Promise(function (success, failure) {
// faire quelque chose d'asynchrone
// quand le resultat r est disponible faire
success(r);
// si une erreur e se produit faire :
failure(e);
})
L'objet Promise contient deux méthodes :
Comment ré-écrire le code ?
let step1 = function (value1) {
return new Promise(function(success, failure) {
//faire ce qu'on faisait avant.
};
};
...
var step4 = function (value4) {
return new Promise(function(success, failure) {
//faire ce qu'on faisait avant.
};
};
let p = new Promise(…);
p.then(step1)
.then(step2)
.then(step3)
.then(step4)
.catch(function(e) {
console.log(e);
};
Autre méthodes utiles :
L'utilisation des promesses est encore simplifiée par une
syntaxe spéciale
async function longFun() {
// code qui prend du temps
return 4
}
Les fonction async ne renvoient
pas directement leur résultat, mais
une promesse qui le calcule.
let x = longFun(); //x ne vaut pas 42!
x.then((res) => { console.log(res); });
Au sein d'une fonction async on peut utiliser le mot
clé await pour « attendre » une promesse :
async otherLongFun () {
let x = await longFun();
let y = await longFun();
let z = await longFun();
return x + y + z;
}