5. Développement Web
Javascript
5.1. Qu'est ce que Javascript ?
D'après Wikipédia : Le langage a été créé en dix jours en mai 1995 pour le compte de la Netscape Communications Corporation par Brendan Eich, qui s'est inspiré de nombreux langages, notamment de Java mais en simplifiant la syntaxe pour les débutants.
Javascript est à la base un langage destiné à dynamiser les pages web du côté client, c'est à dire au niveau du navigateur de l'utilisateur. Le terme dynamiser est à prendre au sens de rendre plus attrayant.
Javascript peut être utilisé de manière procédurale, objet ou fonctionnelle ce qui en fait un langage parfois difficile à maîtriser, sachant que la couche objet est de type prototype ce qui se caractérise par le fait qu'un objet est mutable (modifiable) et non statique.
En effet, les pages web sont à la base des pages dites statiques, c'est à dire dont le contenu ne varie pas une fois chargé au sein du navigateur.
Javascript, généralement abrégé en JS, permet de manipuler des pages (X)HTML au travers de l'API (Application Programming Interface) DOM (Document Object Model), c'est à dire sous forme arborescente.
Le standard (X)HTML définit notamment la possibilité d'assigner à des balises, des actions, sous forme d'attributs (onclick, onsubmit, etc) et d'assigner à ces actions, une fonction Javascript.
Javascript a été standardisé (ECMAScript) au travers d'un consortium appelé ECMA (European Computer Manufacturers Association) qui est une organisation de standardisation de l'industrie informatique.
Attention il ne faut pas confondre le langage Javascript avec le langage Java qui, lui, est plus proche du C++.
5.1.1. AJAX
L'évolution de Javascript est AJAX (Asynchronous JAvascript and XML) qui est la possibilité de lancer des
requêtes asynchrones, en d'autres termes : interroger un serveur, traiter sa réponse dès qu'on la reçoit et
mettre à jour le DOM (Document Object Model).
AJAX permet de créer des RUI (Rich User Interface) comme par exemple les webmails des fournisseurs d'accès internet.
Exemple : on peut cliquer sur un mail pour en visualiser le contenu. Pendant que l'on interroge le serveur et que celui-ci fournit le contenu du mail au navigateur, on peut cliquer sur un bouton "check mail" qui vérifie si de nouveaux mails ont été reçus.
JS permet d'apporter un confort d'utilisation et une ergonomie aux pages web afin d'en faire des applications. De nombreux frameworks ont été créés afin de faciliter certaines tâches :
- gérer les paramètres des formulaires (ex: dojo, jquery)
- introduire des effets d'animations (ex: scriptaculous)
- rendre les tableaux interactifs (ex: dojo)
- dessiner des graphiques (ex: highcharts, exemple)
5.1.2. JSON
JSON (JavaScript Object Notation) est un format textuel pour l'échange d'information qui possède deux avantages :
- il est facile à lire et écrire pour les humains
- il est facilement analysable par un ordinateur
{
"nom" : "Richer",
"prenom" : "Sarah",
"age" : 8,
notes : [ 10, 8, 9 ]
}
JSON permet de transformer des objets Javascript en un texte qui peut alors être envoyé à un serveur. De son côté, le serveur récupère le texte et peut le transformer en objet.
5.1.3. Caractéristiques de Javascript
Javascript est, à la base, un langage exécuté côté client, celà signifie que le code s'exécute dans votre navigateur sur le poste client (votre machine).
Aujourd'hui, Javascript peut également être utilisé côté serveur grâce à Node.js.
Pour des raisons de sécurité, Javascript ne permet pas de lire ou écrire sur votre disque dur. Si c'était le cas, une personne mal intentionnée pourrait récupérer le contenu de votre disque ou endommager des fichiers.
Javascript est un langage :
- de scripts : interprété (et non compilé comme Pascal ou C)
- peu typé : le typage est dynamique, c'est à dire réalisé lors de l'affectation d'une valeur à une variable
- dont la structure du langage (grammaire) repose sur celle du langage C, un langage de programmation impératif, généraliste, traditionnellement utilisé en programmation système (Unix / Linux) et inventé au début des années 1970 par Dennis Ritchie et Ken Thompson
- orienté objet à prototype, c'est à dire que l'on appelle des méthodes associées aux variables et que l'héritage dépend des fonctions liées à l'objet.
En particulier, le fait que Javascript repose sur le langage C implique :
- l'utilisation des mêmes structures de contrôle : if / while / for / switch
- l'utilisation des mêmes structures d'évaluation des expressions arithmétiques et logiques
- la disctinction entre majuscule et miniscule
5.2. Le langage
5.2.1. Variables
5.2.1.a définition
Une variable est définie par un identifiant alphanumérique comme dans la plupart des langages :
- le nom de la variable commence par une lettre (majuscule ou minuscule) ou le caractère souligné : '_'
- puis peut être suivi par des lettres, des chiffres ou le caractère souligné : '_'
- les caractères accentués ne doivent pas être utilisés
Exemple d'identifiants:
- valides : a, A, a_b, pi, x_1_1, _a
- non valides : 12a (commence par un chiffre)
Attention: on a indiqué que Javascript différencie lettres majuscules et minuscules, les identifiants suivants sont donc tous différents : A_b, A_B, a_B
Pour déclarer une variable, il existe plusieurs possibilités :
- soit utiliser le mot clé var
- soit utiliser le mot clé let, mais cela requiert une initialisation
- soit utiliser le mot clé const afin de définir une constante qui sera initialisée
- soit affecter une valeur à un identifiant
var maVariable;
var maVariable1, maVariable2;
annee_de_naissance = 2013;
var x1 = 456, x2;
5.2.1.b portée
La portée d'une variable caractérise son accessibilité. Dans le code suivant :
- factor est accessible dans la fonction product, c'est la cas de toutes les variables déclarées en dehors des fonctions
- n et x ne sont accessibles que dans la fonction product car n est une variable locale à la fonction et x un paramètre de la fonction
var factor = 4;
function product(x) {
var n = x * factor;
return n;
}
Attention : dans une fonction, une variable non déclarée explicitement par var devient globale mais uniquement si la fonction est appelée. Si la fonction n'est pas appelée, la variable est inconnue. Par exemple dans le cas suivant :
function sous_fonction() {
for (i = 9; i <= 10; ++i) {
document.writeln( "sous fonction i = " + i + "<br />");
}
}
function fonction() {
for (i = 1; i <= 10; ++i) {
document.writeln("fonction i = " + i + "<br />");
sous_fonction();
}
}
On affichera :
fonction i = 1
sous fonction i = 9
sous fonction i = 10
Si la variable est déclarée par var dans la fonction elle restera locale à la fonction.
5.2.2. Définition des types
On rappelle que le langage est peu typé. Le langage étant interprété cela signifie que le typage d'une variable est réalisé lors de l'affectation d'une valeur.
Il existe des types élémentaires :
- boolean : booléen
- number : entier ou réel
- string : chaine de caractères
- function : fonction
var entier = -1;
var reel = 3.1415;
var chaine1 = "toto"; // chaine avec double quote (guillemet double)
var chaine2 = 'titi'; // chaine avec simple quote (guillemet simple)
var booleen1 = true;
var booleen2 = (entier > 3);
var fonction = function f(x) { return x*x; }
Ainsi que des types élaborés (ou complexes) :
- Array : tableau associatif
- Date : date
- Object : pour créer de nouveaux objets (non abordé dans ce cours)
Pour déclarer des variables qui sont des instances de types élaborés (en fait des objets), il faut utiliser le nom du type précédé de l'opérateur new :
tab = new Array();
var une_date = new Date();
var naissance = new Date(1970, 8, 30);
On détermine le type d'une variable en utilisant l'instruction typeof :
// types élémentaires
var entier = -1;
var reel = 3.1415;
var chaine1 = "toto";
var chaine2 = 'titi';
var booleen1 = true;
var booleen2 = (entier > 3);
var fonction = function(x) { return x; }
// types complexes
var tableau = new Array();
var une_date = new Date(1970, 8, 30);
typeof entier; // number
typeof reel; // number
typeof chaine1; // string
typeof chaine2; // string
typeof booleen1; // boolean
typeof booleen2; // boolean
typeof fonction; // function
typeof tableau; // object
typeof une_date; // object
if (typeof entier == 'number') {
reel = reel / entier;
}
Attention : on note que les types complexes apparaissent comme des "object". Il faut dans ce cas plutôt utiliser instanceof :
if (typeof tableau == 'object') {
if (tableau instanceof Array) {
// traitement du tableau
}
}
5.2.2.a conversion de types élémentaires
a) Chaine vers entier ou réel :
On utilise les fonctions parseInt ou parseFloat.
var chaine1 = "12";
var chaine2 = "3.14";
var entier = parseInt(chaine1);
var reel = parseFloat(chaine2);
On notera que la fonction parseInt peut prendre un second argument qui est la base de conversion
var n = parseInt("A0", 16); // A0 en hexadécimal = 160 en décimal
var n = parseInt("77", 8); // 77 en octal = 63 en décimal
b) entier ou réel vers chaine :
On utilise les guillemets ou la méthode toString
var entier = 12;
var reel = 3.14;
var chaine1 = "" + entier;
var chaine2 = "" + reel;
// autre possibilité
var chaine1 = entier.toString();
var chaine2 = reel.toString();
On notera que la fonction toString peut prendre un argument qui est la base de conversion
// s = "255 en décimal = ff en hexadécimal"
var s = "255 en décimal = " + (255).toString(16) + " en hexadécimal";
var entier = 255;
var s = "255 en décimal = " + entier.toString(16) + " en hexadécimal";
c) cas problématique :
Si on écrit :
var i = 12 + '4';
var j = '12' + 4;
alors i et j seront égaux à la chaine "124" et non pas à la valeur 16, utilisez alors parseInt pour les chaines.
5.2.3. Expressions arithmétiques et logiques
5.2.3.a opérateurs arithmétiques
- opérateurs classiques : + - * /
- modulo (reste de la division entière) : %
- pré-incrémentation : ++i
- post-incrémentation : i++
- pré-décrémentation : --i
- post-décrémentation : i--
- et binaire : &
- ou (inclusif) binaire : |
- ou (exclusif) binaire : ^
- opérateur de décalage à droite (shift right) : >>
- opérateur de décalage à gauche (shift left) : <<
Certains de ces opérateurs peuvent être combinés avec l'opérateur d'affectation = :
- i += expression est équivalent à i = i + expression
- i -= expression est équivalent à i = i - expression
- i *= expression est équivalent à i = i * expression
- i /= expression est équivalent à i = i / expression
i = 1;
j = ++ i; // j = 2, i = 2
i = 1;
k = i ++; // k = 1, i = 2
i = 3;
k = i << 2; // k = 12 = 3 * 2 * 2
i = 5;
j = 2;
j *= 3; // j = j * 3 = 6
i += j - 7; // i = i + (j - 7) = 5 + (6 - 7) = 4
5.2.3.b opérateurs de comparaison
- opérateurs classiques : < > <= >=
- égalité : ==
- différence : !=
Attention : il ne faut pas confondre l'opérateur d'affectation = et l'opérateur de comparaison pour l'égalité ==
5.2.3.c opérateurs logiques
- ou logique (inclusif) : ||
- et logique : &&
- négation : ~
// (x égal 1) ou (x égal 2)
var booleen = (x == 1) || (x == 2);
// (x égal 1) et (x égal 2)
var booleen = (x == 1) && (x == 2);
// (x égal 1) ou (non(y différent de 2))
var booleen = (x == 1) || (~(y!=2));
5.2.4. Les structures de contrôle
5.2.4.a la conditionnelle if / then / else (si alors sinon)
La conditionnelle, ou si alors sinon s'écrit de manière générique :
if (expression booléenne) {
instructions ;
} else {
instructions ;
}
// if then
if ( x != 0 ) {
y = y / x;
}
// if then else
if ( x != 0 ) {
y = y / x;
} else {
y = 0;
}
// if then else if
if ( x != 0 ) {
y = y / x;
} else if ( x > 0 ) {
y = 1 / x;
} else {
y = 0;
}
5.2.4.b boucle while (tant que)
La boucle while, ou tant que s'écrit de manière générique :
while (expression booléenne) {
instructions ;
}
// additionne les nombres entiers de 1 à 10
var sum = 0;
var i = 1;
while ( i <= 10 ) {
sum = sum + i;
++ i;
}
5.2.4.c boucle do while (répéter)
Il s'agit de l'équivalent du repeat until du Pascal avec une nuance. En Pascal on dit répéter ... jusqu'à, alors qu'en C (ou en Javascript), on dit répéter ... tant que.
do {
instructions ;
} while (expression booléenne);
// additionne les nombres entiers de 1 à 10
var sum = 0;
var i = 1;
do {
sum = sum + i;
++ i;
} while ( i <= 10 );
5.2.4.d boucle for (pour)
Elle fonctionne sur le schéma :
for (initialisation ; condition-de-repetition ; increment ) {
instructions ;
}
En fait la boucle for est une autre manière d'écrire la boucle while.
initialisation;
while (condition-de-repetition) {
instructions ;
increment ;
}
Voici un exemple :
// additionne les nombres entiers de 1 à 10
var sum = 0;
var i;
for ( i = 1 ; i <= 10 ; ++ i) {
sum = sum + i;
}
que l'on peut également écrire :
// additionne les nombres entiers de 1 à 10
for ( sum = 0 , i = 1 ; i <= 10 ; ++ i) {
sum = sum + i;
}
5.2.4.e sortie de boucle (break)
L'instruction break permet de sortir d'une boucle :
// additionne les nombres entiers de 1 à 5
var sum = 0;
var i;
for ( i = 1; i <= 10; ++ i) {
if ( i == 6 ) break;
sum = sum + i;
}
5.2.4.f conditionnelle switch (selon cas)
L'equivalent du case of du Pascal :
switch(x) {
case 0: y = 0; break;
case 1: y = 1; break;
case -1: y = 75; break;
default: y = 999; break;
}
// reviendrait à écrire avec if then else
if (x == 0) {
y = 0;
} else if (x == 1) {
y = 1;
} else if (x == -1) {
y = 75;
} else {
y = 999;
}
Attention : dans la plupart des langages l'instruction case n'admet qu'une valeur scalaire (entier, caractère). En Javascript on peut également utiliser des chaines de caractères ou des réels.
5.2.5. Les fonctions
Les caractéristiques des fonctions sont les suivantes :
- une fonction est déclarée grâce au mot clé function suivi du nom de la fonction, de la liste des paramètres et du corps de la fonction.
- pour sortir d'une fonction en retournant une valeur, on utilise : return expression;
- pour sortir d'une fonction sans retourner de valeur, on utilise : return ;
// fonction sans paramètre
function hello() {
document.write('coucou');
}
// fonction avec deux paramètres
function somme( a, b ) {
if ((typeof a == 'number') && (typeof b == 'number')) {
return a + b;
}
return 0;
}
Pour appeler une fonction il suffit d'utiliser son nom et fournir des paramètres :
// appel de hello
hello();
// appel de somme
var y = 2;
var sum = somme( 1, y );
5.2.5.a passage par valeur ou par adresse ?
La situation est confuse :
- s'il s'agit d'un paramètre de type simple (booléen, entier, réel, chaine) on a un passage par valeur,
- s'il s'agit d'un paramètre de type complexe (tableau, date) on a un passage par adresse.
Voir l'exemple suivant :
function fBool(v) {
v = false;
}
function fInt(v) {
v = 2;
}
function fReal(v) {
v = Math.abs(v);
}
function fStr(v) {
v = v + '2';
}
function fArr(v) {
v.push(3);
}
function fDate(v) {
v.setTime(v.getTime() + 1000000000);
}
var myBool = true;
var myInt = 1;
var myReal = 1.1;
var myStr = "1";
var myArr = new Array(1, 2);
var myDate = new Date("Sep 30, 1970");
fBool(myBool);
fInt(myInt);
fReal(myReal);
fStr(myStr);
fArr(myArr);
fDate(myDate);
print('myBool = ' + myBool);
print('myInt = ' + myInt);
print('myReal = '+ myReal);
print('myStr = '+myStr);
print('myArr = '+myArr.join(","));
print('myDate = '+myDate.toString());
Dont le résultat est :
myBool = true
myInt = 1
myReal = 1.1
myStr = 1
myArr = 1,2,3 // !! on aurait du trouver 1,2
myDate = Sun Oct 11 1970 13:46:40 GMT+0100 (CET) // !! on aurait du trouver 30 Septembre 1970
Pour réaliser un passage par valeur d'un tableau, voici une possibilité qui consiste à dupliquer le tableau passé en paramètre puis à travailler sur la copie :
function fArr(v) {
// début de la copie
vCopy = new Array();
for (i in v) {
vCopy.push(v[i]);
}
// fin de la copie
// on travaille sur la copie
vCopy.push(3);
vCopy[0] = vCopy[0] + 4;
print('vCopy[0] = ' + vCopy[0]);
print('vCopy = '+vCopy.join(","));
}
var myArr = new Array(1, 2);
fArr(myArr);
print('myArr = '+myArr.join(","));
5.2.5.b variable locale ou globale
5.2.6. Les chaînes de caractères (classe String)
5.2.6.a déclaration
On déclare une chaine entre simple ou double quotes (guillemets).
Certains caractères spécifiques sont introduits par un caractère backslash \ :
- \n : nouvelle ligne
- \r : retour chariot
- \t : tabulation
- \b : backspace
- \' : simple quote
- \" : double quote
- \\\\ : backslash
s = 'I don\'t care';
s = "I don't care";
s = "message :\nyou are in C:\\windows";
5.2.6.b length, charAt, charCodeAt
La donnée membre length permet d'obtenir la longueur de la chaine en nombre de caractères et la fonction charAt d'accèder au ième caractère. Le premier caractère de la chaine est en position 0 :
var s = "coucou stéphanie";
document.writeln( "length = " + s.length ); // 16
document.writeln( "charAt(0) = " + s.charAt(0) ); // c
document.writeln( "charCodeAt(0) = " + s.charCodeAt(0) ); // 99
document.writeln( "charAt(9) = " + s.charAt(9) ); // é
document.writeln( "charCodeAt(9) = " + s.charCodeAt(9) ); // 233
5.2.6.c concaténation
On utilise la fonction concat ou l'opérateur + :
var s = "il était";
var t = "une fois";
var u = s + ' ' + t; // u = "il était une fois"
var v = t.concat( " ", s); // v = "une fois il était"
5.2.6.d indexOf, lastIndexOf
Ces fonctions donnent la position d'une sous-chaîne à l'intérieur d'une chaine, on pourra spécifier l'index dans la chaîne à partir duquel on commence la recherche :
var chaine = "coucou dit le coucou tout à coup";
var first = chaine.indexOf( "cou" ); // 0
var last = chaine.lastIndexOf( "cou" ); // 28
var first = chaine.indexOf( "cou", 8 ); // 14
var first = chaine.indexOf( "cout" ); // -1
5.2.6.e search, match, replace
les fonctions suivantes utilisent des expressions régulières pour :
- integer chn.search(regex) : retourne la position de la première sous-chaîne correspondant à regex, retourne -1 si pas d'occurrence
- array chn.match(regex) : recherche les occurrences de l'expression régulière
- string chn.replace(regex, str) : remplace l'expression régulière par la chaine str
var chaine = "Wed Sep 30 1970";
var pos = chaine.search( /[0-9]{4}/ ); // pos = 11
var a = chaine.match( /[0-9]+/g ); // a = [30 1970]
var s = chaine.replace( / ([0-9]{2}) ([0-9]{4})/, " -\$2 \$1-" );
// s = "Wed Sep -1970 30-"
5.2.6.f substr, substring et slice
Ces fonctions permettent d'extraire des sous-chaînes
- chn.substring(position_début, position-fin)
- chn.substr(position_début, nombre-de-caractères)
- chn.slice(position_début, nombre-de-caractères-en-moins)
Par exemple les trois expressions suivantes vont extraire la chaine "coucou␣t" :
var chaine = "coucou dit le coucou tout à coup";
var sub_string = chaine.substring( 14, 22 );
var sub_string = chaine.substr( 14, 8 );
var sub_string = chaine.slice( 14, -10 );
5.2.6.g toLowerCase, toUpperCase
Les fonctions toLowerCase et toUpperCase permettent de transformer respectivement en minuscules et majuscules une chaîne de caractères.
var s = "tOTO";
var t = s.toLowerCase(); // t = "toto"
5.2.7. Les tableaux
Les tableaux en javascript sont des tableaux associatifs qui fonctionnent avec une clé non forcément entière : à une clé (key) on associe une valeur (value).
5.2.7.a déclaration
Il existe 3 façons de déclarer un tableau :
// 1: utilisation des crochets []
a1 = [ 'a', 'b', 3, true ];
// 2: création et initialisation
a2 = new Array( 'a', 'b', 3, true );
// 3: création puis remplissage
a3 = new Array();
a3[ 0 ] = 'a';
a3[ 1 ] = 'b';
a3[ 2 ] = 3;
a3[ 3 ] = true;
On peut également déclarer des tableaux associatifs (clé non entière) :
colors = new Array();
colors[ "red" ] = "#ff0000";
colors[ "green" ] = "#00ff00";
colors[ "blue" ] = "#0000ff";
5.2.7.b présence d'une valeur
Pour un tableau simple on utilisera indexOf(valeur), par contre pour un tableau associatif avec clé non entière on utilisera le mot clé in :
var a = [ 1, 2, 8, 9, 25 ];
a.indexOf( 9 ); // 3, valeur 9 présente à l'indice 3 du tableau
a.indexOf( 12 ); // -1, élément non présent
var b = new Array();
b[ "a" ] = 65;
b[ "b" ] = 66;
b[ "0" ] = 48;
b[ "1" ] = 49;
if ( "0" in b ) {
...
}
5.2.7.c parcours des éléments
Soit on parcourt suivant l'indice (clé), soit suivant les valeurs :
for ( i = 0; i < a3.length; ++i) {
document.writeln( a3[ i ] + " " );
}
// red : #ff0000 green : #00ff00 blue : #0000ff
for ( indice in colors ) {
document.writeln( indice + " : " + colors[ indice ] + " ");
}
5.2.7.d ajout, suppression
Les méthodes associées aux tableaux sont de type pile ou file
- pile :
- push : ajoute à la fin
- pop : supprime et retourne le dernier élément
- file :
- shift : supprime et retourne le premier élement
- unshift : ajoute au début
- on peut également ajouter à tout moment un nouvel élément à n'importe quel endroit du tableau en fonction de son indice
var a = new Array();
a.push( "une" );
a.push( "fois" );
a.unshift( "était" );
a.unshift( "il" );
// affiche : il était une fois
document.writeln( a.join(" ") );
5.2.7.e tri
On utilise la fonction sort, on peut également lui associer un paramètre qui est une fonction de comparaison :
a = new Array( "il" , "était", "une", "fois" );
a.sort();
// affiche : fois il une était
document.writeln( a.join(" ") );
a = [ 1, 2, 7, 4, 25, -1, 8 ];
// <b>tri par défaut (alphabétique)</b> : -1 1 2 25 4 7 8
a.sort();
document.writeln( a.join(" ") );
// tri <b>numérique</b> ascendant : -1 1 2 4 7 8 25
// nécessite une fonction de comparaison
a.sort( function( a, b ) { return a - b; } );
document.writeln( a.join(" ") );
// tri numérique descendant : 25 8 7 4 2 1 -1
a.sort( function( a, b ) { return b - a; } );
document.writeln( a.join(" ") );
5.2.7.f décomposition (String.split), composition (Array.join)
La méthode split(chn) associée à une chaine de caractères permet de décomposer la chaine en un tableau en la découpant en fonction d'une sous-chaine chn.
La méthode join(chn) associée à Array permet de transformer un tableau en une chaine en regroupant les éléments et les séparant par chn.
var s = "a..b.c....d";
var a = s.split( ".." );
// affiche a-b.c--d
document.writeln(a.join("-") );
5.2.8. La classe Math
Cette classe définit un moyen d'utiliser les fonctions comme le logarithme, l'exponentielle, sinus, cosinus, ...
document.writeln( Math.sin( Math.PI ) ); // 1.2246063538223773e-16
document.writeln( Math.cos( Math.PI ) ); // -1
document.writeln( Math.sqrt( 2 ) ); // 1.4142135623730951
Voir également : w3schools.js.Math
5.2.9. La classe Date
5.2.9.a création
La classe Date permet de stocker un timestamp (que l'on pourraît traduire par intervalle de temps), en l'occurrence il s'agit du nombre de millisecondes écoulées depuis le 1er Janvier 1970 à minuit.
// Mon Jan 14 2013 18:04:28 GMT+0100 (CET)
var d = new Date();
// Wed Sep 30 1970 00:00:00 GMT+0100 (CEST)
var d = new Date("Sep 30, 1970");
// Mon Jan 12 1970 14:46:40 GMT+0100 (CET)
var d = new Date(1000000000);
// Wed <span class="red">Sep</span> 30 1970 00:00:00 GMT+0100 (CEST)
var d= new Date(1970, <span class="red">8</span>, 30);
var timestamp = Date.parse('Sep 30, 1970'); // 23497200000
Attention : lors de la définition de la date avec année, mois ,jour, le mois de Janvier a pour valeur 0, Février 1, ... On a donc indiqué 8 pour le mois de Septembre.
5.2.9.b méthodes
On dispose d'un certain nombre de méthodes associées à la classe Date :
- getFullYear() : année sur 4 chiffres
- getMonth() : mois (0 à 11)
- getDate() : jour du mois (1 à 31)
- getDay() : jour de la semaine
- getHours()
- getMinutes()
- getSeconds()
- getMilliSeconds() : nombre entre 0 et 999
- getTime() : nombre de millisecondes depuis le 1er Janvier 1970 à minuit
- ...
- setFullYear (year, month, day): fixe la date
- setTime (milli)
- setHours (hour,min,sec,millisec)
- ...
5.3. La couche objet en Javascript
5.3.1. Les objets sans classe
On peut créer des objets sans utiliser de classe car toute variable est un objet :
jean = {
nom: "richer",
prenom: "jean",
ddn: "19700930"
};
mathieu = {
nom: "richer",
prenom: "mathieu",
ddn: "19750312"
};
document.write( JSON.stringify(jean) +"<br />" );
On peut également ajouter un champ ou une méthode à un objet existant :
jean.salaire = 3000.0;
function augmente_salaire( pourcentage ) {
this.salaire = Math.round( (1 + pourcentage/100.0) * this.salaire );
}
jean.augmente = augmente_salaire
mathieu.augmente = augmente_salaire
jean.augmente( 10 );
document.write( JSON.stringify(jean) +"<br />" );
Mais pour mathieu on n'a pas défini de champ salaire. Le code s'exécutera quand même mais sans erreur !
mathieu.augmente( 10 );
document.write( JSON.stringify( mathieu ) +"<br />" );
// l'appel à une fonction inconnue, comme :
// mathieu.fonction_inconnue();
// générera une erreur :
// TypeError: mathieu.fonction_inconnue is not a function
5.3.2. Les objets définis sous forme de classes
On peut définir des classes et les étendre en utilisant class et extends. On fait référence aux champs grâce au mot clé this et à une méthode définie dans la classe mère grâce au mot clé super :
class Personne {
constructor( nom, prenom ) {
this.nom = nom;
this.prenom = prenom;
}
toString() {
return this.nom + ", " + this.prenom;
}
};
class Employe extends Personne {
constructor( nom, prenom, salaire ) {
super( nom, prenom );
this.salaire = salaire;
}
toString() {
return super.toString() + ", " + this.salaire + " €";
}
};
elon_musk = new Employe( "Musk", "Elon", 3000000 );
jean_michel = new Employe( "Richer", "Jean-Michel", 3000 );
document.write( elon_musk.toString() + "<br />" + jean_michel.toString() );
5.3.3. Extension avec une fonction
On peut par la suite étendre une classe en ajoutant une fonction à son prototype :
Employe.prototype.augmente = function() {
this.salaire = Math.round( this.salaire * 1.1);
}
elon_musk.augmente();
jean_michel.augmente();
document.write( elon_musk.toString() + "<br />" + jean_michel.toString() );
5.3.4. Extension avec un champ
Dans ce cas, on se trouve face à un problème lié au fait que JSON.stringify ne reportera le champ que si une instance est modifiée pour ce champ :
Employe.prototype.rang = "big boss";
// JSON.Stringify ne retourne pas le champ 'rang'
document.write( JSON.stringify( elon_musk ) + " " + elon_musk.rang + "<br />" );
// mais si on modifie le 'rang' pour une instance, alors celui-ci
// apparaît avec l'utilisation de JSON.stringify
jean_michel.rang = "chercheur";
document.write( JSON.stringify( jean_michel ) );
5.4. Interaction avec le navigateur
L'utilisation de Javascript au sein du navigateur impose de pouvoir interagir avec celui-ci. On dispose de deux moyens pour afficher de l'information :
- la méthode alert( "message" ) qui ouvre une fenêtre popup afin d'afficher un message et qui a pour but d'attirer l'attention de l'utilisateur
- les méthodes console.log( "message" ), console.error( "message" ), console.error( "message" ) qui affichent des messages dans la console, visibles si vous passez en mode Outils de développement (Ctrl+Maj+I sous Google Chrome par exemple)
- les méthodes document.write( "message" ) et document.writeln( "message" ) pour écrire directement dans le document (X)HTML
5.5. La manipulation du DOM
Un des intérêts de Javascript est qu'il permet de manipuler le DOM. On dispose pour cela d'un ensemble de fonctions de base. Malheureusement, le résultat rendu par certaines fonctions est étrange et contient différents types d'information :
- document.getElementById( "my_id" ); pour récupérer un élément défini par un identifiant dans la page (X)HTML
- document.getElementsByTagName( "p" ); pour récupérer une liste d'éléments qui correspondent à une balise
- document.getElementsByClassName( "rouge" ); pour récupérer une liste d'éléments qui ont une classe CSS définie
Malheureusement le traitement ultérieur du résultat de certaines de ces fonctions est parfois étrange (cf cette page.
Dans ce cas il est préférable d'utiliser querySelectorAll :
const matches = document.querySelectorAll("p");
const matches = document.querySelectorAll("div.note, div.alert");
Voir la documentation sur le site de Mozilla.
5.6. Les frameworks Javascript
5.6.1. Les CDN
Un réseau de diffusion de contenu (RDC) ou en anglais Content Delivery network (CDN) est constitué d’ordinateurs reliés en réseau à travers Internet et qui coopèrent afin de mettre à disposition du contenu ou des données à des utilisateurs.
On trouvera notamment cdnjs.com qui référence nombre de frameworks javascript ainsi que jsdelivr.com En particulier :
5.6.2. Quelques frameworks
Vous trouverez sur cette page, une liste comparative des frameworks Javascript liés au développement web généraliste.
Des frameworks plus spécifiques existent comme HighCharts qui permet de réaliser des graphiques.
- JQuery est probablement l'un des frameworks les plus utilisé pour la manipulation du DOM, la gestion des évènements, les animation et les requêtes AJAX. Il existe également JQueryUI qui se focalise sur l'interaction avec l'utilisateur
- Dojo ou DojoToolkit est l'équivalent de JQuery et JQueryUI
- Angular.io (anciennement AngulaJS) : the modern web developer's platform
- React.js est une bibliothèque JavaScript pour créer des interfaces utilisateurs à base de composants
- Vue.js : an approachable, performant and versatile framework for building web user interfaces
- Bootstrap : powerful, extensible, and feature-packed frontend toolkit. Build and customize with Sass, utilize prebuilt grid system and components, and bring projects to life with powerful JavaScript plugins
5.7. AJAX
La technologie AJAX (Asynchronous JAvascript and XML) qui combine en fait trois technologies :
- l'utilisation de Javascript
- pour lancer des requêtes asynchrones
- et en traiter le résultat (XML, HTML, JSON, texte)
fait partie de l'aspect dynamique des pages web introduit grâce à Javascript.
Le fait que la requête soit asynchrone impose que l'interface du navigateur n'est pas bloquée entre le moment où on lance la requête et le moment où on récupère les données.
5.7.1. La classe XMLHttpRequest
Pour réaliser une requête asynchrone il faut créer une instance de la classe XMLHttpRequest. En fonction du navigateur, il faudra créer un objet d'un autre type (Microsoft). La création d'une requête ressemble donc plutôt au code suivant :
/**
* Création d'une instance de la classe requête asynchrone
* en fonction du navigateur
*/
function getXMLHTTPRequest() {
try {
req = new XMLHttpRequest();
} catch(exc1) {
try {
req = new ActiveXObject( "Msxml2.XMLHTTP" );
} catch(exc2) {
try {
req = new ActiveXObject( "Microsoft.XMLHTTP" );
} catch(exc3) {
req=false;
}
}
}
return req;
}
Avec les frameworks comme JQuery, la création de l'objet adéquat est transparente pour l'utilisateur (voir ci-après).
5.7.2. Récupération de données au format texte
var request = getXMLHTTPRequest();
// Appel de l'URL avec la méthode GET
// true indique que la requête est asynchrone
request.open( "GET", "http://....", true );
// indique quelle méthode sera appelée
// quand on obtiendra une réponse
request.onreadystatechange = process_data;
// appel de la requête dans paramètre
request.send( null );
/**
* Fonction qui traite la réponse obtenue
*
*/
function process_data() {
if ( request.readyState == 4) {
if ( request.status == 200) {
var my_text = request.responseText;
...
}
}
}
Le traitement de la réponse passe par une première étape qui vérifie que le traitement de la requête n'a pas rencontré d'erreur. On doit s'intéresser aux deux variables de la requête status et readyState qui maintiennent l'état d'avancement et de complétion (terminaison) de la requête :
0 |
request not initialized |
1 |
server connection established |
2 |
request received |
3 |
processing request |
4 |
request finished and response is ready |
Variable readyState
200 |
OK |
204 |
No Content |
205 |
Reset Content |
400 |
Bad Request |
404 |
Not Found |
... |
autres codes d'erreurs |
Variable status
Il faut que :
- status = 200
- et readyState = 4
pour qu'on puisse traiter les données car on a reçu les données et aucune erreur n'a été générée.
Il est généralement nécessaire de traiter les erreurs éventuelles en les signalant par un message d'alerte.
5.7.3. Récupération de données au format XML/XHTML
Dans le cas ou le serveur renvoie des données au format XML, il faudra les récupérer en utilisant la variable responseXML de la requête. Par exemple, si on récupère le fichier :
<doc>
<today> 30/09/2022 </today>
<message> Joyeux Anniversaire </message>
</doc>
On en extraira les champs de la manière suivante :
var my_doc = request.responseXML;
var today = my_doc.getElementsByTagName( "today" )[ 0 ].innerHTML
var message = my_doc.getElementsByTagName( "message" )[ 0 ].innerHTML
5.7.4. Récupération de données au format JSON
Si les données sont au format JSON, soit, par exemple :
{
"today" : "30/09/2022",
"message" : "Joyeux Anniversaire"
}
On utilisera la variable responseText que l'on transformera en objet grâce à JSON.parse() :
var my_obj = JSON.parse( request.responseText );
console.log( my_obj.today + ' ' + my_obj.message );
5.7.5. Utilisation de JQuery
Le framework JQuery permet de réaliser des requêtes AJAX. Il existe plusieurs manières de réaliser l'appel, j'ai choisi ici d'utiliser une requête généraliste :
$.ajax({
type: 'GET',
dataType: "json",
url: 'ajax_get_data_as_json.php',
success: function( data ) {
$( "#id_text").val(
data.today + "\n" + data.message.replace( "<br />", "\n" )
);
},
error: function( xhr, status, error ) {
alert('An error occurred ! ' + status + ' ' + error);
}
});
- il s'agit d'une requête de type GET
- et les données seront retournées au format JSON (dataType)
- il faut redéfinir success en tant que fonction qui traitera les données une fois la requête terminée avec succès
- ainsi que error qui sera déclenchée en cas d'erreur
5.7.6. Exemples AJAX
Voici quelques exemples qui reprennent ce que nous venons de voir :
- Exemple 1 : XMLHttpRequest + données au format texte
- Exemple 2 : XMLHttpRequest + données au format XML
- Exemple 3 : XMLHttpRequest + données au format JSON
- Exemple 4 : JQuery + données au format JSON
- Exemple 5 : JQuery + données au format texte pour remplir un select
5.8. Exercices
Exercice 5.1
Créer un programme Javascript qui permet de trier un tableau d'entiers. On initialisera le tableau avec des valeurs aléatoires (Math.random()) et on créera une fonction qui trie le tableau en utilisant un tri bulle et qui accepte un tableau en paramètre.
Exercice 5.2
Modifiez le programme précédent en implantant le tri sous forme d'un tri rapide.
Exercice 5.3
Récupérez les données d'un formulaire contenant un champ nom et un champ salaire puis modifier les nom en le passant en majuscules et en augmentant le salaire de 10%. Utilisez document.getElementById().
Exercice 5.4
Reprendre l'exercice précédent mais utilisez le framework JQuery.
Exercice 5.5
Reprendre l'exercice précédent mais utilisez le framework JQuery et une requête Ajax qui envoie les données du formulaire à un script PHP.
Exercice 5.6
Créer une hiérarchie d'objets en Javascript (Point, Rectangle, Circle) ainsi qu'un tableau d'objets et dessiner ces objets dans un canvas.
Exercice 5.7
Créer une classe Mask composée :
- d'un tableau data de 16 entiers ayant des valeurs entre 0 et 1.
- d'un entier total qui donne le nombre de valeurs à 1 dans data
Créer un constructeur qui prend en paramètre les valeurs du tableau data sous forme de chaîne de caractères et qui met à jour le champ total.
Créer une fonction contains(m) qui vérifie si le masque m passé en paramètre est contenu dans le masque, c'est à dire que les valeurs du tableau qui sont à 1 dans m le sont aussi dans le masque.
Tester sur quelques exemples.