Tutoriel JavaScript de base

De EduTech Wiki
Aller à la navigation Aller à la recherche
JavaScript
◀▬
à améliorer intermédiaire
2015/11/12
Prérequis
Voir aussi

Introduction

Ce tutoriel présente un survol des caractéristiques principales du langage JavaScript relatives à l’utilisation « côté client », c’est-à-dire l’utilisation la plus fréquente dans des pages/applications web à l’intérieur d’un navigateur.

Rappel de la structure d'une page web

Avant d'aborder JavaScript, il est utile de rappeler la structure d'une page web qui se compose généralement de trois éléments :

  • HTML : cet élément détermine le contenu de la page, c'est-à-dire les éléments textuels et graphiques affichés à l'écran.
  • CSS : cet élément détermine la mise en page, la manière de présenter les éléments HTML de la page. On peut déterminer à travers les CSS les couleurs, les polices, l'alignement des éléments, etc.
  • JavaScript : cet élément ajoute des interactions et des comportements (ou effets) au contenu et/ou à la présentation de la page. Ces phénomènes permettent de modifier la page sans la nécessité d'actualiser le navigateur.

Présentation de JavaScript

JavaScript est un langage de scripting qui a vécu plusieurs évolutions dans le temps, ce qui complique en quelque sorte son apprentissage parce que le code et les tutoriels présents dans le web varient fortement en fonction de leur date. Non seulement le code a changé dans le temps, mais aussi la "philosophie" de JavaScript. Au début, JavaScript était considéré comme un outil utilisé principalement dans les formulaires web. Aujourd'hui, grâce à l'évolution des navigateurs web, JavaScript est devenu l'outil le plus utilisé pour les interactions client-side des pages web, mais il est également utilisé dans le développement d'applications pour les dispositifs mobiles, dans le développement de logiciels desktop et même dans le développement server-side. Malgré la similarité du nom, Java et JavaScript sont deux langages différents.

Outils pour le développement et le débug

Pour développer en JavaScript seulement deux outils sont strictement nécessaires :

  • Un navigateur web
  • Un éditeur de texte

Des outils supplémentaires peuvent sans doute rendre le développement plus aisé. Voici une liste de ces outils :

Console JavaScript

Pour contrôler la présence d'erreurs d'une page directement dans un navigateur web ou pour essayer du code, vous pouvez utiliser les Consoles d'erreurs des navigateurs.

  • Internet Explorer : Menu Outils > Outils de développement (ou F12)
  • Firefox : F12 ou plus de fonctionnalités via l'extension Firebug
  • Chrome : Menu Outils > Console JavaScript (ou F12)
  • Safari : D'abord dans les Options > Avancées cocher la case "Afficher le menu Développement dans la barre des menus", puis CTRL+Alt+I ou CTRL+Alt+C
  • Opera: Menu Page > Outils de Développement > Opera Dragonfly (ou CTRL+Shift+I)
Console des erreurs en Google Chrome

La console JavaScript est un endroit très utile pour tester du code JavaScript pour deux raisons :

  • On peut saisir directement du code dans la console et l'évaluer. Dans l'image suivante, les lignes précédées par > sont des lignes avec du code, et les lignes précédées par <- proposent le résultat de l'évaluation du code.
La console du navigateur évalue directement du code.


  • On peut communiquer avec la Console JavaScript. Par exemple la notation console.log() permet d'écrire un message dans la Console. Pour ceux qui ont utilisé Flash, cette instruction est similaire à la fonction trace() de Flash. Voici un exemple :
<script>
window.onload = function() {
  for(var i = 0; i < 5; i++) {
       console.log("Cycle actuel : " + i);
  }
}
</script>

Le résultat de ce script dans la console JavaScript est le suivant :

La méthode log() de l'objet Console permet d'afficher des messages dans la console JavaScript.

Une fois terminé la partie de développement, il est mieux d'enlever toute référence à la Console.

Syntaxe de JavaScript

JavaScript est un langage de scripting, il permet donc d'écrire des algorithmes qui sont évalués et exécutés par un interprète. Pour que l'interprète puisse comprendre le code source, il faut respecter les règles syntaxiques du langage JavaScript. Ces règles déterminent principalement deux aspects :

  1. Qu'est-ce qu'un code JavaScript valide?, car la présence d'erreurs dans le code arrête l'exécution du script;
  2. Si le code est valide, qu'est-ce qu'il est censé faire en termes de Input/Output?

Pour déterminer quel est l'objectif du code, l'interprète JavaScript lit le code et le transforme en instructions (statement en anglais). Les instructions sont une suite d'expressions qui combinent les éléments du langage. Voici ci-dessous une liste des éléments principaux du langage avec leur syntaxe:

Commentaire

Il existe deux manières de commenter le code JavaScript selon le nombre de lignes utilisées par le commentaire.

Une seule ligne :

//Si le code est limité à une seule ligne (c'est-à-dire qu'il n'y a pas de retour à la ligne)

Plusieurs lignes :

/*
 * Si le code
 * est sur
 * plusieurs lignes
*/

Variables

La déclaration d'une variable se fait de cette manière :

var nomDeLaVariable = "Valeur de la variable";

Le nom des variables doit observer les règles suivantes :

  • Ne peut pas être un mot réservé par le langage (voir une liste ici : http://www.w3schools.com/js/js_reserved.asp)
  • Peut se composer exclusivement de caractères alphanumériques, underscore (_) et signe du dollar ($)
  • Le premier caractère ne peut pas être un chiffre
//Exemple de variables correctes
var monWiki123 = "EduTechWiki";
var $monWiki123 = "EduTech Wiki";
var _____monWiki123 = "EduTechWiki";
//Exemple de variables non correctes
var 123wiki = "Faux";
var aujourd'hui = "Faux";

Il est possible de déclarer une variable sans lui assigner une valeur. Dans ce cas la variable x sera "undefined" :

var x;

On peut associer à une variable différents types de valeurs (texte, chiffres, ...) mais également des fonctions ou des objets (voir plus bas). Dans le premier cas on parle de données primitives, et dans le deuxième d'objets.

Les types de variables acceptés sont :

  • String : chaîne des caractères (e.g. var a = "Bonjour")
  • Number : chiffres et décimales (e.g. var a = 12)
  • Boolean : vrai/faux (e.g. var a = true)
  • null et undefined

Il existe également de nombreux types d'objets dont les plus utilisés sont :

  • Object
  • Array
  • Function

Objets

Un objet est un élément qui se compose d'une ou plusieurs associations "clé-valeur". On déclare un objet de cette manière :

 var monObjet = {
     clé1: "valeur",
     clé2: "valeur",
     clé3: "valeur"
 }

Exemples:

 var agesAmis = {Jean:20, Julie:25, Jan:23, Jolan:27};
 var sexeAmis = {Jean:"homme", Julie:"femme", Jan:"homme", Jolan:"homme"};

On peut par la suite récupérer le contenu d'un objet à travers la notation monObjet.clé1, monObjet.clé2, etc. Exemple:

> agesAmis.Jean
20

Ce type de notation peut être utilisé également pour associer une valeur :

 monObjet.clé1 = "valeur";
 monObjet.clé2 = "valeur";

Dans le langage lui-même sont présents des objets qui disposent de leurs propres associations clés-valeurs. Par exemple lorsqu'on utilise document.write() on accède à la valeur-méthode "write" de l'objet "document". Cette valeur correspond dans ce cas à une fonction qui ajoute du contenu au document. Les valeurs des objets peuvent en effet représenter des valeurs (texte, chiffres) mais également des fonctions ou même d'autres objets.

Array

Un array (tableau) est un groupe d'éléments qui disposent d'un index pour les mettre en ordre. L'index est associé automatiquement à partir de zéro.

 var mesCours = ["STIC I", "STIC II", "STIC III", "STIC IV"];

On peut ensuite récupérer un élément en utilisant la syntaxe "[..]". mesCours[0] veut dire que l'on récupère le premier élément du array. Dans la plupart des langages de programmation, on commence à numéroter à partir de 0.

 var STIC_I = mesCours[0];
 var La_suite = mesCours[1];

Dans une console, on peut taper:

> STIC_I
"STIC I"
> La_suite
"STIC II"

Fonctions

Une fonction est une sorte de processus qui détermine un résultat final et le rend disponible, un schéma d'actions à accomplir. Ce processus peut être basé sur des informations initiales qui sont passées à la fonction en tant qu'arguments. L'intérêt des fonctions consiste à les réutiliser plusieurs fois.

Il existe des fonctions préétablies dans le langage, comme par exemple la fonction alert() qui affiche à l'écran une boîte contenant un message. JavaScript permet de déclarer également ses propres fonctions de cette manière :

function nomDeMaFonction() {
    //Processus de la fonction
}

Si on veut ajouter des arguments à la fonction, il faut les insérer dans les parenthèses et les séparer par des virgules (arg1, arg2, arg3). Par exemple la fonction suivante affiche dans une boîte alert le nom passé dans l'argument :

function afficheLeNom(nom) {
    alert(nom);
}

Pour exécuter cette fonction il faudra donc l'utiliser dans le code de notre page web de la manière suivante : afficheLeNom("Batman").

Operateurs

Les opérateurs permettent de manipuler des valeurs.

//Concaténation de texte
var a = "Hello";
var b = "world!";
alert(a + " " + b); //Hello world!
//Opérateurs mathématiques
var a = 2 + 3; //5
var b = 10 - 5; //5
var c = 2 * 3 //6
var d = 9 / 3; //3

Les opérateurs logiques AND (&) et OR (|), ainsi que les opérateurs de comparaison (==, !==, ...) sont expliqués dans la partie sur les structures de contrôle.

Structures de contrôle

Les cycles conditionnels permettent d'exécuter du code si une ou plusieurs conditions s'avèrent vraies. Les conditions sont testées à l'aide des éléments if, else if et else.

Le code suivant exécute un redirect (window.location) à la version du EduTech Wiki correspondante à la langue, et affiche un message si la langue n'est ni français, ni anglais. Ci-dessous on parle français, mais vous pouvez changer...

 var lang = "Français" //  par exemple .....
 if(lang == "Français") {
     window.location = "http://edutechwiki.unige.ch/fr/Accueil";
 } else if (lang == "Anglais") {
     window.location = "http://edutechwiki.unige.ch/en/Main_Page";
 } else {
     alert("EduTech Wiki n'est pas encore disponible dans votre langue!");
 }

Comme vous pouvez le voir, la variable lang est testée à l'aide de l'opérateur == qui détermine s'il y a correspondance entre la variable et la valeur. Les opérateurs de comparaison sont les suivants :

  • == détermine si les deux éléments sont similaires dans leurs valeurs
  • !== détermine si les deux éléments sont différents dans leurs valeurs
  • === détermine si les deux éléments sont similaires dans leurs valeurs et types
  • !=== détermine si les deux éléments sont différents dans leurs valeurs et types
  • >, >=, <, <= déterminent le rapport des éléments en fonction d'une échelle

Parfois il est nécessaire de tester plusieurs conditions à la fois, c'est-à-dire que plus d'une condition doivent s'avérer vraies au sein du même test. Pour ce faire, on utilise les opérateurs logiques :

  • & ou AND : implique que les deux conditions liées par cet opérateur soient vraies
  • | ou OR : implique que au moins une des deux conditions liées par cet opérateur soit vraie

Souvent on utilise deux opérateurs du même type (&& ou ||) à l'intérieur de la même relation pour renforcer le lien par rapport à d'autres opérations logiques. Pour déterminer quel type d'opération logique doit être exécuté avant les autres on peut également utiliser des parenthèses.

Voici quelques exemples :

 if(mois == "décembre" && jour == 25) {
     alert("C'est Noël");
 }

 if(jour == "samedi" || jour == "dimanche") {
     alert("C'est le weekend!");
 }

Lorsque les conditions à tester sont plusieurs, au lieu d'utiliser plusieurs if, else if et else, on peut utiliser le cycle switch :

 switch( lang ) {
     case "Français":
     window.location = "http://edutechwiki.unige.ch/fr/Accueil";
     break;

     case "Anglais":
     window.location = "http://edutechwiki.unige.ch/en/Main_Page";
     break;

     default:
     alert("EduTech Wiki n'est pas encore disponible dans votre langue!");
 }

Le command break est nécessaire afin d'arrêter l'exécution du code pour la condition.

Boucles

Les boucles sont des éléments qui permettent de répéter un processus pour un nombre de fois établi (cycle for), ou jusqu'à ce que une certaine condition s'avère (cycle while).

La fonction for nécessite 3 arguments :

  • Une définition d'une variable d'entrée (point de départ de la boucle)
  • Une définition d'une variable de sortie (point final de la boucle)
  • Une définition de l'incrémentation de la variable à chaque passage

Voici un exemple de cycle qui aura lieu 20 fois :

for(var i = 0; i < 20; i++) {
    //code à exécuter à chaque fois
}

Le cycle while évalue une condition et exécute le cycle jusqu'à ce que cette condition soit vraie. Ceci implique implicitement qu'un changement doit s'avérer à l'intérieur du cycle afin que cette condition soit fausse à un certain point, sinon le cycle ne s'arrêterait jamais. Voici le même résultat du cycle for vu plus haut dans le texte, mais avec la notation while :

var i = 0;
while (i < 20) {
    //code à exécuter à chaque fois
    i++;
} 

La notation i++ à la fin du code ajoute une unité à la variable i, de cette manière la condition évaluée dans le cycle while sera fausse après 20 passages, et par conséquent le cycle while s'arrêtera. Il existe également la possibilité d'utiliser le cycle do... while qui contrairement au simple cycle while s'exécute au moins la première fois, même si la condition évaluée est fausse. Par exemple ce code affichera une fois la boîte d'alerte :

do {
    alert("Une fois seulement");
} while (1 == 2);

La boucle for ... in permet de boucler sur les propriétés énumérables d'un objet.

var myObj = {x:20, y:30, nounours:40}; 
for (var chaine in myObj) 
{ 
    console.log (chaine + "=" + myObj[chaine]); 
}

Donne:

x=20 
y=30
nounours=40

Attention: for ..in ne doit pas être utilisé pour des arrays pour lesquels l'ordre des indices est important, car l'ordre des itérations peut varier ou encore dit autrement, on ne sait pas quelle propriété sera choisie à quel moment...

La boucle for each ...in (JS 1.6) permettait d'itérer sur les valeurs des propriétés. Elle est replacée par l'instruction for ... of dans la dernière version 6 de ECMAScript). Cette dernière est plus versatile et parcourt tous les objets sur lesquels on peut itérer dans toutes les structures.

Les fonctions en JavaScript

Comme on l'a vu brièvement dans la syntaxe de base, les fonctions sont des ensembles d'instructions qui forment un processus. Toutes les instructions qui se trouvent à l'intérieur de la fonction seront exécutées lorsque la fonction sera utilisée. La "vie" d'une fonction se caractérise par deux phases :

  • Une phase de définition dans laquelle le fonctionnement interne de la fonction est établi (i.e. ce que la fonction est censée faire)
  • Une phase d'invocation (i.e. d'utilisation) de la fonction dans un contexte où son fonctionnement interne est utile à la logique de programmation

Il existe néanmoins la possibilité en JavaScript de combiner les deux phases, dans ce cas on parle de fonction anonyme ou immédiate (voir plus bas dans la section).

Définition d'une fonction

Pour définir une fonction il faut la nommer. On peut définir une fonction une seule fois, donc chaque fonction doit avoir un nom unique. La syntaxe pour définir une fonction est la suivante :

function nomDeLaFonction(arguments) {
    //Instructions
}

Une fonction accepte pas d'arguments, un ou plusieurs arguments. Les arguments sont des références à des valeurs qui sont externes à la fonction et qui seront utilisées à l'intérieur. Si la fonction nécessite plusieurs arguments, il faudra les séparer par une virgule.

À l'intérieur d'une fonction on peut utiliser tout le code JavaScript qu'on peut utiliser en dehors. Il faut juste faire attention au "scope" des variables. En effet, les variables que l'on définit à l'extérieur d'une fonction seront disponibles aussi à l'intérieur d'une fonction, mais les variables déclarées à l'intérieur d'une fonction seront disponibles seulement à l'intérieur de la fonction elle-même. Voici un exemple :

var dispoPartout = "Je suis disponible aussi dans les fonctions";

function alertMesVariables() {
     var dispoIci = "Je suis disponible seulement dans cette fonction";
     alert(dispoPartout + " " + dispoIci);
}

var executerFonction = alertMesVariables();//boite avec les deux messages affichées

console.log(dispoPartout); //Le message de la variable dispoPartout sera affiché dans la console
console.log(dispoIci);//La variable dispoIci n'est pas définie --> Erreur dans la console

Invocation d'une fonction

Pour invoquer une fonction, c'est-à-dire exécuter les instructions contenues à l'intérieur de la fonction à un moment donné dans le code, il faut simplement écrire le nom de la fonction et éventuellement passer les arguments nécessaires à son fonctionnement interne.

var maFonction = nomDeMaFonction(arguments);

Retour d'une fonction

Les instructions d'une fonction sont censées aboutir à un certain résultat qui peut être une action, telle qu'afficher une boîte d'alerte, mais également fournir le résultat d'une manipulation des données dans l'endroit du code où cette fonction a été invoquée. Pour renvoyer un résultat on utilise l'instruction return. Cette fonction détermine que la fonction a exécuté son "rôle" et que le processus à son intérieur est terminé.

function addition(a, b) {
    var total = a + b;
    return total;
}

Cette fonction renvoie le résultat d'une addition entre les deux arguments de la fonction. On peut utiliser plusieurs notations return dans la même fonction, par exemple dans le cadre d'un cycle conditionnel. On exploite dans ce cas le fait que cette instruction termine l'exécution du code à l'intérieur d'une fonction.

function controlerMoyenne(note) {
    var message = "Examen réussi";
    if(note >= 4) {
         return message;
    } else {
         message = "Examen échoué";
    }
    alert(message);
}

L'alerte de cette fonction sera déclenchée seulement si la note est inférieure à 4 même si elle se trouve en dehors de la structure de contrôle, parce que si la note est supérieure à 4, le return arrêtera l'exécution de la fonction et donc l'alerte ne sera pas prise en compte.

Fonctions anonymes

JavaScript permet de créer des fonctions qui n'ont pas de nom dans la perspective d'une utilisation immédiate et non répétée. Les fonctions anonymes sont souvent utilisées en tant qu'arguments d'autres fonctions. Par exemple la fonction setTimeout() de l'objet window accepte deux arguments :

  1. Une fonction à exécuter
  2. Un temps en millisecondes avant que la fonction soit déclenchée

Voici comment une fonction anonyme peut être passée en tant que premier argument :

setTimeout(function() { alert("Message après 3 secondes"); }, 3000);

Cette notation est équivalente à :

function messageApres3secondes() {
    alert("Message après 3 secondes");
}
setTimeout(messageApres3secondes, 3000);

Arguments dans une fonction

Les fonctions de JavaScript acceptent des arguments (i.e. paramètres) qui sont optionnels. Ces arguments sont utilisés à l'intérieur du corpus de la fonction. Il y a deux manières pour récupérer un argument à l'intérieur de la fonction :

  1. L'argument est spécifié dans la définition de la fonction et à l'intérieur il est utilisé avec le nom de la référence
  2. L'argument n'est pas spécifié dans la définition et il est récupéré grâce à l'array arguments qui associe un index à partir de 0 à chaque argument passé par référence

Voici un exemple pour chaque modalité :

//1.
function addition(a, b) {
    return a + b;
}
//2.
function addition() {
    return arguments[0] + arguments[1];
}

La deuxième méthode est particulièrement utile si on ne sait pas à l'avance combien d'arguments seront passés à une fonction. Par exemple on peut configurer notre fonction addition() afin qu'elle calcule la somme des arguments indépendamment de leur nombre :

function addition() {
    var numArgs = arguments.length;
    var total = 0;
    for(var i=0; i < numArgs; i++) {
         total += arguments[i];
    }
    return total;
}
var monTotal = addition(11,23,45,21,97);

Objets en JavaScript

Définition d'un objet

Comprendre les objets en JavaScript équivaut à comprendre le langage lui-même, car pratiquement tout est un objet en JavaScript : les types de données (String, Number, Array, …) sont des objets, l’élément « document » utilisé pour accéder aux différents éléments d’une page web est un objet, et ainsi de suite. Par conséquent, la définition d’un objet doit forcément être assez générale pour prendre en compte toutes les différentes applications des objets :

  • Un objet est un élément qui contient d’autres éléments, même d'autres objets.

Les éléments contenus dans un objet peuvent être de deux types :

  1. Propriétés : c’est l’équivalent des variables dans un objet, car une propriété n’est qu’une valeur associée à un objet.
  2. Méthodes : c’est l’équivalent des fonctions dans un objet, car une méthode permet d’exécuter une certaine action sur un objet, souvent en relation avec ces propriétés.

Voyons tout de suite un exemple. Vu que pratiquement tout est un objet en JavaScript, prenons une simple suite de caractères (i.e. string).

var phrase = "Ceci n’est pas un Wiki" ;

La variable phrase est maintenant un objet de type String, un objet qui fait partie du langage JavaScript de base, et donc les propriétés et les méthodes sont accessibles à tout endroit dans le code. Voici deux exemples :

console.log(phrase.length) ; //22
console.log(phrase.toUpperCase()) ; //CECI N'EST PAS UN WIKI

On vient d’utiliser une propriété (i.e. length) et une méthode (i.e. toUpperCase()) associés à un objet de type String. De plus, on vient également d'utiliser la méthode log() de l'objet console pour afficher le contenu dans le navigateur web - tout est un objet! Pour mieux comprendre encore cette idée, on aurait même pu tout simplement utiliser la propriété et la méthode directement avec la suite de caractères, sans utiliser une variable :

"Ceci n'est pas un Wiki".length ;
"Ceci n'est pas un Wiki".toUpperCase() ;

L’accès aux propriétés et méthodes d’un objet se fait normalement à travers une notation « par points ». Vu qu’une propriété est une variable, pour y accéder il faut tout simplement ajouter son nom après l’objet et le point :

  • Objet.propriété

Au contraire, une méthode étant une fonction, il faut ajouter également les deux parenthèses.

  • Objet.méthode()

Cette notation peut être "enchaînée", par exemple la notation suivante permet d'associer à la variable monTexte le contenu d'une balise HTML avec id="mon-id", c’est-à-dire la propriété innerHTML de l’objet element récupéré avec la méthode getElementById(id) de l’objet document.

var monTexte = document.getElementById("mon-id").innerHTML

JavaScript met à disposition des développeurs trois types d’objets différents :

  1. Les objets globaux du langage de base (i.e. « native objects ») : il s’agit d’objet constitutifs du langage lui-même et qui sont par conséquent accessibles dans n’importe quel endroit dans le code et indépendamment de l’utilisation de JavaScript côté client ou serveur dans une page web, dans une application mobile, logiciel desktop, etc.
  2. Les objets mis à disposition par l’environnement : il s’agit d’objets qui dépendent directement de l’endroit dans lequel le code est interprété. La plupart du temps, ceci correspond au navigateur internet de l’utilisateur lui-même, qui met donc à disposition des objets tels que window ou document (voir plus bas dans la page).
  3. Les objets personnalisés : il s’agit d’objets que le développeur définit lui-même selon les nécessités particulières à l’application

Objets globaux (Native Objects)

Les objets disponibles dans le langage de base constituent les bases de l’API du langage lui-même, c’est-à-dire les propriétés et les méthodes que le langage considère utile pour définir les algorithmes nécessaires à manipuler les données dans une application. Voici de suite une liste non exhaustive de certains de ces objets (pour la liste complète : consulter par exemple la documentation Mozilla).

String

L'objet String permet d'exécuter des manipulations sur des chaînes de caractères. Voici un exemple pour la méthode toUpperCase() qui transforme les lettres en majuscules.

var msg = "Bonjour";
msg.toUpperCase(); //BONJOUR

Number

L'objet Number permet d'exécuter des manipulations sur des nombres. Voici un exemple pour la méthode toFixed() qui transforme un chiffre en caractère avec une précision décimale fixée.

var num = 6.749737898732;
var numPrint = num.toFixed(2); //6.75

Math

L'objet Math permet d'exécuter des manipulations mathématiques sur des chiffres. Voici un exemple pour trouver un nombre aléatoire entre 1 et 100 :

var randomNumber = Math.floor((Math.random() * 100) + 1);

Date

L'objet Date permet d'exécuter des manipulations sur les dates. La gestion des dates n'est pas simple en JavaScript. Par exemple la méthode getMonth() qui identifie le mois de l'année en chiffres ne propose pas les mois de 1 à 12, mais plutôt de 0 à 11. Donc le mois 10 n'est pas octobre comme on pourrait s'imaginer, mais plutôt novembre. Voici un exemple pour obtenir le jour du mois (de 1 à 31) :

var d = new Date();
var aujourdhui = d.getDate();

Objets personnalisés

JavaScript permet de créer ses propres objets avec les propriétés et méthodes souhaitées. Les propriétés sont représentées par des données, tandis que les méthodes par des fonctions.

Définition d'un objet

La définition d'un objet peut se faire de différentes manières. Les notations suivantes définissent le même objet appelé Cours :

//1.
var Cours = {nom: "STIC I", periode: "Automne", nombreExercices: "8"};
//2.
var Cours = {}; //Aussi var Cours = new Object();
Cours.nom = "STIC I";
Cours.periode: "Automne";
Cours.nombreExercices: "8";

Les noms des propriétés ne doivent pas suivre la notation des variables, mais s'ils ne la suivent pas, il faut les insérer entre guillemets comme les valeurs :

var Cours = { nomRespecte: "STIC I", "nom-ne-respecte-pas": "STIC I"}

On peut associer à un objet aussi des méthodes, encore une fois de différentes manières dont le résultat est équivalent :

//1.
var Cours = {};
Cours.nom = "STIC I";
Cours.afficherNom = function () { return "STIC I" };
//2.
function afficherNomDuCours () {
    return "STIC I";
}
var Cours = {};
Cours.nom = "STIC I";
Cours.afficherNom = afficherNomDuCours;

Utilisation des objets

Une fois définit l'objet, on peut l'utiliser facilement à travers la notation "par points" pour propriétés dont le nom respecte la notation des variables ou les méthodes. Pour les noms des propriétés qui ne respectent pas la nomination des variables, il faudra utiliser la notation "à Array". Voici des exemples :

var Cours = { nomRespecte: "STIC I", "nom-ne-respecte-pas": "STIC I"};
Cours.maMethode = function () { console.log("Je suis une méthode de l'objet Cours"); };
var nomDuCours1 = Cours.nomRespecte;
var nomDuCours2 = Cours["nom-ne-respecte-pas"];
var ecrireDansConsole = Cours.maMethode();//Il faut utiliser les parenthèses

L'élément this dans les Objets

Parfois il est nécessaire d'accéder à d'autres propriétés ou méthodes d'un objet à l'intérieur de l'objet lui-même. Dans ce cas, l'objet est représenté par la notation this. Voici un exemple illustratif :

var Cours = {};
Cours.nom = "STIC I";
Cours.afficheLeNom = function () { alert(this.nom) };
var afficher = Cours.afficheLeNom();

Définir des objects prototypes

Les notations qu’on a vues plus haut pour définir un objet sont utiles pour définir un seul objet de ce type, ce qu’on appelle une « instance » de l’objet. Il est également possible de créer plusieurs instances d’un objet, pour ce faire il faut le définir à travers une fonction « constructrice », qui crée des objets prototypes. Voici un exemple pour créer deux instances d’un objet « Tutoriel » :

function Tutoriel(argument, niveau) {
  this.argument = argument;
  this.niveau = niveau;
  this.printTutorielInfo = function () {
    return 'Tutoriel de niveau ' + this.niveau + ' sur ' + this.argument;
  }
}
var tutorielJavaScriptBase = new Tutoriel('JavaScript', 'intermédiare');
var tutorielNodeJs = new Tutoriel('Node.js', 'avancé');

console.log(tutorielJavaScriptBase.printTutorielInfo()); // --> Tutoriel de niveau intermédiare sur JavaScript
console.log(tutorielNodeJs.printTutorielInfo()); // --> Tutoriel de niveau avancé sur Node.js

L’objet Tutoriel fonction correctement, mais son fonctionnement interne peut être amélioré, car à présent chaque fois qu’on crée une instance de cet objet, le navigateur doit créer trois éléments :

  1. La propriété argument
  2. La propriété niveau
  3. La méthode pour récupérer les infos sur le Tutoriel

De ces trois éléments, la méthode est commune à toute instance de l’objet, car elle se limite à fournir les deux propriétés qui différencient les différents tutoriels. Pour éviter que cette méthode soit créée pour chaque instance, on peut exploiter la propriété « prototype » commune à tout objet. Cette propriété permet d’ajouter une propriété ou une méthode communs à toute instance du même objet. Dans le cas du tutoriel, on peut effacer la fonction printTutorielInfo() à l’intérieur de la fonction constructrice, et la déclarer en tant que méthode prototype :

function Tutoriel(argument, niveau) {
  this.argument = argument;
  this.niveau = niveau;
}

Tutoriel.prototype.printTutorielInfo = function () {
  return 'Tutoriel de niveau ' + this.niveau + ' sur ' + this.argument;
}
var tutorielJavaScriptBase = new Tutoriel('JavaScript', 'intermédiare');
var tutorielNodeJs = new Tutoriel('Node.js', 'avancé');

console.log(tutorielJavaScriptBase.printTutorielInfo()); // --> Tutoriel de niveau intermédiare sur JavaScript
console.log(tutorielNodeJs.printTutorielInfo()); // --> Tutoriel de niveau avancé sur Node.js

Ce type de programmation à objects peut être très utile par exemple pour les jeux. Voici un exemple incomplet de comment un object "Monster" pourrait se présenter. D'abord, on définit la fonction constructrice qui accepte trois paramètres: (1) le type de monstre, (2) sa position X, et (3) sa position Y:

//Définir la fonction constructrice des Monstres, avec les éléments particuliers à chaque instance.
function Monster(name, x, y) {
  this.name = name;
  this.x = x;
  this.y = y;
}

Ensuite, on définit les propriétés et les méthodes communes à toute instance qui permettent de faire bouger le monstre et de le tuer. On crée également une fonction qui fourni des informations sur l'état du monstre à un certain moments dans le jeu:

//Définir les propriétés et les méthodes communes à toute instance d'un monstre.
Monster.prototype.health = 100;
Monster.prototype.isAlive = true;
Monster.prototype.isHit = function (damage) {
  this.health -= damage;
  if(this.health <= 0) {
    this.isAlive = false;
  }
}
Monster.prototype.moveUp = function () {
  this.y += 10;
}
Monster.prototype.moveDown = function () {
  this.y -= 10;
}
Monster.prototype.moveRight = function () {
  this.x += 10;
}
Monster.prototype.moveLeft = function () {
  this.x -= 10;
}
Monster.prototype.printInfo = function () {
  if(!this.isAlive) {
    return "Le " + this.name + " a été tué!";
  }
  return "Le " + this.name + " se trouve aux coordonnées [" + this.x + ":" + this.y + "] et il lui manque " + this.health + " avant de disparaître.";
}

Maintenant on peut simuler le jeu en créant deux monstres:

//Simulation du jeu avec deux monstres, un Dragon et un Goblin. 
var firstMonster = new Monster('Dragon', 0, 0);
firstMonster.moveLeft();
firstMonster.moveUp();
firstMonster.isHit(50);
console.log(firstMonster.printInfo()); // --> Le Dragon se trouve aux coordonnées [-10:10] et il lui manque 50 avant de disparaître.

var secondMonster = new Monster('Goblin', 25, -15);
secondMonster.moveDown();
secondMonster.isHit(5);
console.log(secondMonster.printInfo()); // --> Le Goblin se trouve aux coordonnées [25:-25] et il lui manque 95 avant de disparaître.

firstMonster.moveUp();
firstMonster.moveLeft();
firstMonster.isHit(60);
console.log(firstMonster.printInfo()); // --> Le Dragon a été tué!

JavaScript et le navigateur web

L'avantage de JavaScript côté client consiste dans le fait que les navigateurs web disposent d'un "moteur" qui permet d'évaluer le code JavaScript et l'exécuter à chaque fois qu'une page web, contenant du code JavaScript, est téléchargée par l'utilisateur. Ceci est possible surtout grâce à deux phénomènes :

  1. L'inclusion de code JavaScript dans des pages HTML ;
  2. L'existance d'un objet global window qui permet à JavaScript d'interagir avec le navigateur web.

Utilisation du code JavaScript dans une page HTML

Il existe trois manières différentes d'utiliser du code JavaScript dans une page web :

  1. Fichier externe : le code est écrit dans un fichier avec extension .js
  2. Code "inline" : le code est écrit directement dans la page web elle-même
  3. Attribut des balises (déconseillé) : le code est écrit dans des attributs des balises des éléments HTML de la page. Cette option, utilisée souvent dans le passé, est aujourd'hui fortement déconseillée et ne sera par conséquent pas illustrée dans ce tutoriel.

Les trois différents manières peuvent être utilisées en même temps, il n'est pas nécessaire de choisir une seule manière pour toute la page.

Fichier externe

Dans le cas d'utilisation d'un fichier externe, ce fichier doit être créé avec l'extension .js. Dans ce fichier doit être contenu seulement du code JavaScript. Le code peut commencer dès la première ligne, il ne faut pas déclarer le type de fichier par exemple à travers une balise XML.

Pour rendre disponible le code d'un fichier externe dans une page web, il faut inclure le lien au fichier dans la balise HTML script et plus précisément à travers l'attribut src. Voici un exemple :

<script src="dossier/fichier.js"></script>

Veuillez noter que la balise script doit être fermée avec la balise de clôture même si à l'intérieur d'une balise avec attribut src il ne faut pas insérer de code.

Le lien au fichier .js peut être relative ou absolu. Le mauvais pointage d'un fichier externe est une des raisons les plus communes d'erreur dans le code JavaScript et il est par conséquent la première chose à contrôler en cas de problèmes.

On utilise des fichiers externes souvent dans ces conditions :

  • Le même fichier contient du code qui est utilisé dans plusieurs pages d'un site, ce qui évite la nécessité de l'écrire dans toutes les pages. De cette manière, une modification au code doit se faire à un seul endroit et sera automatiquement activé dans toutes les pages.
  • Le fichier est une bibliothèque JavaScript
  • Il y a beaucoup de code écrit

Code inline

Une autre manière très utilisée d'inclure du code JavaScript consiste à écrire le code directement à l'intérieur de la balise script. Dans ce cas, il ne faut pas déclarer l'attribut src. Voici un exemple :

<script>
alert("Bonjour!");
</script>

La balise script peut contenir seulement du code JavaScript. Dans des exemples sur le web vous pouvez parfois trouver des balises script qui présentent aussi l'attribut type="text/javascript". Cet attribut n'est plus nécessaire car tout navigateur considère automatiquement le code inséré dans cette balise comme du code JavaScript.

On utilise du code "inline" souvent dans ces conditions :

  • Le code doit être exécuté précisément à cet endroit dans la page, par exemple parce qu'il ajoute du texte ou des éléments HTML.
  • Le code est spécifique à une seule page du site est le code n'a pas de probabilité d'être utilisé ailleurs
  • Le code est court
  • Le code sert à configurer des options ou initialiser une bibliothèque JavaScript

Placement de la balise script

Un élément auquel il faut faire attention est le placement de la balise script dans la page HTML. Il faut en effet tenir compte de la manière progressive de charger une page des navigateurs web. Avec le code JavaScript on fait souvent référence à des éléments du DOM (i.e. des balises HTML contenu dans la page). Il faut faire attention dans ces cas à ce que cet élément soit déjà disponible au navigateur. Un exemple illustre cette problématique....

Nous allons récupérer le texte d'un paragraphe avec id="mon-texte" avec la fonction document.getElementById("mon-texte").innerHTML ; et ensuite nous utiliserons la fonction document.write() pour écrire ce contenu. En d'autres termes, le comportement attendu de la page est d'obtenir deux fois exactement le même texte. Les deux exemples du code suivant sont exactement les mêmes, mais dans un cas, la balise script est positionnée avant le paragraphe, et dans l'autre cas après.

<!doctype html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Untitled Document</title>
</head>
<body>
<script>
var texte = document.getElementById("mon-texte").innerHTML;
document.write(texte);
</script>
<p id="mon-texte">Bonjour!</p>

</body>
</html>

Si le code est avant le paragraphe, le script n'a pas accès à l'élément du DOM qui correspond au paragraphe. Donc aucun texte ne sera écrit par la fonction write().

<!doctype html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Untitled Document</title>
</head>
<body>
<p id="mon-texte">Bonjour!</p>
<script>
var texte = document.getElementById("mon-texte").innerHTML;
document.write(texte);
</script>
</body>
</html>

Au contraire, si le code est placé après le paragraphe, son contenu sera réécrit par le script et apparaîtra donc à l'écran.

Même s'il existe des fonctions pour déclencher le code seulement une fois que toute la structure du DOM a été chargée dans le navigateur (e.g. window.onload), il est une bonne pratique d'inclure les balises script juste avant la balise de clôture /body :

<!doctype html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Untitled Document</title>
</head>
<body>

<script>
//Mon code est mieux ici!
</script>
</body>
</html>

L'objet global window

JavaScript dépend de l'environnement dans lequel il est exécuté à la fois pour afficher les résultats des expressions (i.e. le output), mais également pour recevoir des inputs. Dans JavaScript côté client, cet environnement est représenté par le navigateur web et la communication I/O entre JavaScript et le navigateur web se fait à travers l'objet global window. Plus concrètement cela signifie que :

  1. JavaScript peut "intercepter" tous les événements qui concerne la fenêtre du navigateur comme par exemple les clicks, les changements d'URL, le scolling de la page, etc.
  2. JavaScript peut modifier certaines propriétés de la fenêtre, y compris son contenu.

Les deux opérations sont possible justement grâce à l'objet global window qui, en tant qu'objet, possède des propriétés et des méthodes. Comprendre l'objet global window peut contribuer à bien comprendre le langage, car en réalité tout le code source écrit en JavaScript côté client peut se diviser en deux catégories :

  1. Le code qui exploite les propriétés et méthodes mises à disposition par l'objet window
  2. Le code qui ajoute des propriétés (e.g. des variables) ou des méthodes (e.g. des fonctions) à l'objet global window

En effet, lorsqu'on déclare une variable, ce que nous sommes en train de faire c'est tout simplement d'ajouter une propriété avec le nom de la variable à l'objet global window. En d'autres termes, les deux lignes de code suivantes sont équivalentes :

var cours = "STIC I";
window.cours = "STIC I";

Le même principe s'applique aux fonctions :

function addTwo(x) {
  return x + 2;
}
addTwo(4); // -> 6
window.addTwo(7); --> 9

En raison du fait que tout appartient à l'objet window, on peut éviter de le déclarer à chaque fois. Le même principe s'applique aux propriétés et méthodes déjà disponibles. Par example la fonction alert() - qui affiche une boîte popup avec un message - est en réalité la méthode window.alert().

De suite une liste non exhaustive des propriétés et méthodes déjà disponible avec l'objet window, pour une liste exhaustive voir la référence de l'objet Window sur W3Schools.

Les boîtes popup de JavaScript

Pour le débutant, créer quelques simples boîtes popup permet se lancer dans la programmation. On peut par exemple poser une question à un utilisateur et ensuite la traiter, puis afficher le résultat.

JavaScript possède 3 sortes de boîtes popup :

  1. Les boîtes d'alerte
  2. Les boîtes de confirmation
  3. Les fenêtres de saisies.

Vous pouvez structurer votre message dans vos boites en insérant '\n' à la fin de vos phrases. Cela permettra de revenir à la ligne.

alert ('Première ligne.\n Deuxième ligne.')
Alert.jpg

Les boites d'alerte

Elles affichent un message. Elles servent généralement à donner un message à un utilisateur ou à indiquer un message d'erreur. La boîte d'alerte contient un bouton 'Ok'.

Il faut utiliser la fonction alert(), c'est-à-dire l'équivalent de window.alert()

<html>
    <head>
        <script type="text/javascript">
            function gagné()
            {
                alert("Bravo vous avez trouvé");
            }
        </script>
    </head>
    <body>
        <input type="button" onclick="gagné()" value="Trouver">
    </body>
</html>
Confirm.jpg

Les boîtes de confirmation

La fonction confirm() affiche une boite de confirmation. L'utilisateur a alors le choix entre 'OK' et 'annuler'.

<html>
    <head>
        <script type="text/javascript">
            function confirmer()
            {
                var reponse=confirm("Continuer l'operation en cours ?");
                if (reponse==true)
                {
                    alert("Vous avez cliqué sur OK");
                }
                else
                {
                    alert("Vous avez cliqué sur Annuler");
                }
            }
        </script>
    </head>
    <body>
        <input type="button" onclick="confirmer()" value="Choix" />
    </body>
</html>

Les fenêtres de saisie

Il est possible de créer une fenêtre pour saisir une valeur grâce à la fonction prompt(). La fonction prend deux paramètres : le premier est l'invitation à saisir du texte et le second propose un texte par défaut.

Après avoir entré une valeur, l'utilisateur peut cliquer sur 'ok' ou sur 'annuler.

Exemple : ici quand l'utilisateur clic sur 'Ok' la valeur saisie est indiqué dans la fenêtre d'alerte ensuite.

<html>
    <head>
        <script type="text/javascript">
            function saisir()
            {
                var reponse=prompt("Identification, veuillez saisir votre prenom","mon prenom");
                //si la réponse est non nul ou vide - donc l'utilisateur a appuyé sur ok
                if (reponse!=null && reponse!="")
                {
                    alert("Votre prenom est :"+reponse);
                } 
                 //autre cas : si l'utilisateur clic sur 'Annuler'
                else {
                    alert("Operation interrompue")
                }
            }
        </script>
    </head>
    <body>
        <input type="button" onclick="saisir()" value="Saisir mon prenom" />
    </body>
</html>
Prompt.jpeg


Prompt2.jpeg

Les fonctions liées au temps

Grâce à l'objet global window il est possibile d'exécuter du code en fonction du temps, plus spécifiquement :

  • setTimeout() permet d'exécuter du code une seule fois après une période de temps définie ;
  • setInterval() permet d'exécuter du code à des intervalles regulières de temps.

setTimeout()

La syntaxe pour utiliser la fonction setTimeout() est la suivante :

setTimeout(function,milliseconds, [param1,param2,...]);

Les paramètres sont optionnels, tandis que la fonction à exécuter et le temps en milliseconds sont obligatoires. Voici un example qui affiche une boite d'alerte après 5 seconds (i.e. 5 * 1000 milliseconds) :

var afficherApres5seconds = setTimeout(function () { alert("Message"); }, 5000);

Il est également possibile de définir d'abord une fonction et ensuite passer son nom comme référence dans la fonction setTimeout() :

function alertMessage() {
  alert("Message");
}
var afficherApres5seconds = setTimeout(alertMessage, 5000);

Associer la fonction setTimeout() à une variable est utile si on veut annuler l'exécution de la fonction avant que la période de temps définie avec la notation :

clearTimeout(variable);

En ajoutant cette ligne de code à l'exemple précédent, la fonction alertMessage() ne sera pas déclenchée :

function alertMessage() {
  alert("Message");
}
var afficherApres5seconds = setTimeout(alertMessage, 5000);
clearTimeout(afficherApres5seconds);

setInterval()

La fonction setInterval est similaire à setTimeout() si ce n'est pour le fait que le code sera exécutée chaque X milliseconds. La syntaxe reste par contre la même :

setInterval(function,milliseconds, [param1,param2,...]);

Voici un exemple qui affiche dans la console un message chaque 3 seconds (sans arrêt si la page ne sera pas fermée ou après changement de URL) :

var chaque3seconds = setInterval(function () { console.log("...encore 3 seconds"); }, 3000);

Pour limiter les cycles on peut utiliser un conteur et utiliser la fonction clearInterval direcement à l'intérieur de la fonction invoquée par setInterval() :

var count = 0;
var cinqFois = setInterval(function () {
 count++; 
 console.log(count);
 if(count == 5) {
   clearInterval(cinqFois);
 }
}, 2000);

JavaScript et le DOM

Une des fonctionnalités plus utilisées de JavaScript est sa capacité d'interagir dynamiquement avec le DOM, c'est-à-dire la structure hiérarchique des balises HTML d'une page web. C'est notamment grâce à la manipulation des éléments du DOM qui s'avèrent les interactions sur une page : apparition d'un message, déplacement d'un élément d'un endroit à l'autre, changement de la taille d'une police, du couleur, etc.

Ces manipulations sont possibles grâce à l'objet document qui fait partie de l'objet global window (voir plus haut dans la page). Les propriétés, méthodes ainsi que les événements associés à cet objet permettent de manipuler le DOM.

Manipulation des éléments du DOM

Trouver un élément

Trois méthodes permettent d'identifier un élément dans la structure du document :

  • document.getElementById(id élément) : identifie un élément avec l'attribut id="..."
  • document.getElementsByTagName(nom de la balise) : identifie un ou plusiuers éléments avec le nom de la balise
  • document.getElementsByClassName(une ou plusieurs classes) : identifie un ou plusieurs éléments avec l'attribut class="..."

Une méthode plus générale est également disponible à travers les méthodes :

  • document.querySelector(css selector)  : cette méthode accepte des identifiants plus complexes par rapports aux trois méthodes vus plus haut dans la page, mais elle est également plus flexible, car elle permet d'identifier les éléments grâce aux selecteurs CSS. Cette méthode identifie le premier élément qui respecte les critères du selecteur.
  • document.querySelectorAll(css selector) : même principe mais le résultat est un array avec tous les éléments qui respectent le critère de sélection.

Voici quelques exemples d'utilisation :

document.querySelectorAll("a.external") //cette méthode identifie toutes les balises a avec classe "external"
document.querySelectorAll("h1,h2,h3") //cette méthode identifie toutes les titres de h1 à h3

Cette fonction peut également être utilisée à l'intérieur des éléments du DOM :

var monParagraphe = document.getElementById("monTexte");
monTexte.querySelector("span").innerHTML = "Nouveau texte du span";

Ce code identifie le premier élément span à l'intérieur du paragraphe avec id="monTexte" et change le contenu textuel.

Modifier un élément

On peut modifier différentes caractéristiques d'un élément une fois identifié dans le document par exemple à travers ces propriétés :

  • element.innerHTML : modifie le contenu de la balise de l'élément sélectionné
  • element.attribute : modifie un attribut de la balise de l'élément sélectionné
  • element.style.property : modifie les propriétés de style de la balise de l'élément sélectionné

Ajouter ou supprimer un élément

On peut ajouter des éléments qui n'existent pas dans la structure de base du document ou supprimer des éléments existants. Exemples :

  • document.createElement() : définit un nouvel élément HTML
  • document.appendChild() : ajoute un élément à la structure existante
  • document.replaceChild() : remplace un élément existant par un autre élément
  • document.removeChild() : supprime un élément présent dans la structure

Exemples de manipulation

Dans la page suivante, 4 types de manipulation ont lieu lorsque la page a été chargée. L'expression window.onload = function () { ....} associe directement une fonction anonyme (sans nom) qui sera exécutée lorsque la page charge:

<!doctype html>
<html>
<head>
    <meta charset="UTF-8">
    <title>JavaScript - exemple de manipulation du DOM</title>
</head>
<body>
 
<h1>JavaScript - exemple de manipulation du DOM</h1>

<p id="p1">Premier paragraphe.</p>
<p id="p2">Deuxième paragraphe.</p>
<p id="p3">Troisième paragraphe</p>
<p>Quatrième paragraphe.</p>
<div>Je ne suis pas un paragraphe!</div>

<script>

window.onload = function() {
  //1. On remplace le texte du premier paragraphe
  var p1 = document.getElementById("p1");
  p1.innerHTML = "Le texte du premier paragraphe a été modifié par JavaScript";
 
  //2. On ajoute une image au deuxième paragraphe
  var p2 = document.getElementById("p2");
  var image = document.createElement("img");
  image.src = "http://lorempixel.com/200/200/abstract";
  p2.appendChild(image);
 
  //3. On supprime le troisième paragraphe
  var p3 = document.getElementById("p3");
  document.getElementsByTagName("body")[0].removeChild(p3);
 
  //4. On change la couleur du texte des paragraphes
  var pp = document.getElementsByTagName("p");
  for(var i = 0; i < pp.length; i++) {
    document.getElementsByTagName("p")[i].style.color = "#F00";
  }
}
</script>
</body>
</html>

Les manipulations 1. et 2. ne nécessitent pas d'explication supplémentaire, tandis que la 3. et la 4. sont un peu plus complexes. Il faut considérer en effet que la méthode getElementsByTagName() renvoie un array d'éléments, c'est-à-dire un groupe d'éléments avec un indice (voir plus haut dans la page pour les Array). On identifie un élément d'un Array avec la notation nomDuArray[indice].

Dans la manipulation 3. nous avons identifié d'abord la balise body car il s'agit de la balise "parent" du paragraphe 3 qu'on veut supprimer. Bien qu'il n'y ait généralement qu'une seule balise body, la méthode getElementsByTagName() renvoie néanmoins un Array, dont le premier et seul élément est notre balise body. Vu que les indices des Array commence à 0, pour identifier notre élément body nous devons ajouter l'indice [0] à la méthode getElementsByTagName("body").

Le même principe concerne la manipulation 4., dans laquelle le Array contient par contre plusieurs éléments. Pour changer chaque élément, il faut par conséquent un cycle. Nous avons créé ce cycle à l'aide de la fonction for et nous avons déclaré en tant que fonction de sortie la propriété length de l'Array lui-même. Cette propriété identifie le nombre d'éléments présents dans l'Array.

Tester cet exemple

Ce type de manipulation est plutôt complexe, raison pour laquelle des bibliothèques JavaScript (e.g. jQuery) offrent des méthodes plus faciles pour accéder aux éléments du DOM.

Événements du DOM

Les événements du DOM permettent d'identifier l'interaction de l'utilisateur avec la page, par exemple à travers les mouvements de la souris, les touches du clavier, etc. Les événements concernent également les éléments eux-mêmes, par exemple dans le cas de l'objet window ou encore des éléments d'un formulaire.

L'événement onload

L'événement onload() est déclenché lorsqu'un élément (ou tout le DOM) a été téléchargé dans le navigateur web. Une notation qui est très utilisée et qui, par contre, nécessite de déclarer explicitement l'objet window concerne l'événement onload :

  • window.onload() : permet de déclencher du code une fois que la page a été chargée dans le navigateur. Il faut être attentif au fait que cette fonction peut être déclarée seulement une fois dans chaque page. Si plusieurs déclarations de window.onload sont disponibles dans la même page, seulement celle déclarée en dernière sera exécutée.
<script>
window.onload = alert("Je ne serais pas affiché");
window.onload = alert("Je serais affiché");
</script>

Un autre problématique relative à cette fonction concerne le fait que l'événement onload s'avère lorsque tous les éléments du DOM ont bien été chargés, y compris images, feuilles de style, etc. Ceci peut parfois retarder le déclenchement de l'événement et par conséquent toutes les éléments interactifs associés à cet événements ne seront pas disponibles.

L'événement onload() peut être également associé à d'autres éléments du DOM internes ou externes, comme par exemple les images, les iframes, etc.

Événements liés à la souris

Parmi les événements plus utilisés dans l'interaction avec le DOM il y a sans doute les événements liés aux mouvements et clicks de la souris. Voici une liste non exhaustive de ces événements :

  • click : l'événement est déclenché avec un click de la souris
  • mouseover : l'événement est déclenché lorsque la souris passe sur l'élément
  • mouseout : l'événement est déclenché lorsque la souris quitte un élément

Pour attribuer un événement à un élément il faut procéder ainsi :

  1. Identifier l'élément dans la structure du DOM (voir plus haut dans cette page)
  2. Spécifier un événement déclencheur à travers une des notations disponibles (e.g. document.getElementById("mon-bouton").onclick)
  3. Associer à cet événement un "event handler" (gestionnaire d'événement), c'est-à-dire le processus (normalement une fonction) qui doit se mettre en marche lorsque l'événement se produit

Il y a deux manières d'associer un événement à un élément :

  • Utiliser la propriété de l'événement qui se compose de "on" + événement (élément.onclick, élément.onmouseover, élément.onmouseut, ...) à la quelle on associe une fonction :
    • élément.onévénement = function () { ... }
  • Utiliser la méthode addEventListener qui prévoit deux arguments : l'événement et la fonction à exécuter :
    • élément.addEventListener(événement, fonction)

Le gestionnaire d'événement peut être une fonction déjà définie ou anonyme. Il faut cependant faire attention au fait qu'un gestionnaire d'événement est une référence à la fonction est non pas l'exécution de la fonction elle-même. En d'autres termes, il ne faut pas utiliser les parenthèses dans un gestionnaire d'événement :

function faireQuelqueChose() {
    //code
}
mon-element.mon-evenement = faireQuelqueChose; //OK!
mon-element.mon-evenement = faireQuelqueChose(); //Faux, de cette manière la fonction sera exécutée de toute manière, sans attendre l'événement déclencheur

Veuillez par contre noter que si on associe comme gestionnaire une méthode d'un objet, alors il faudra de toute manière insérer les parenthèses.

var o = {}:
o.faireQuelqueChose = function () {
  //code
}
mon-element.mon-evenement = o.faireQuelqueChose; //Faux
mon-element.mon-evenement = o.faireQuelqueChose(); //OK!

On peut également utiliser une fonction anonyme en tant que gestionnaire d'événement :

mon-element.mon-evenement = function() {
    console.log("L'événement a eu lieu");
}

Enfin, il est possible d'utiliser la méthodeélément.addEventListener(événement, gestionnaire) au lieu de la notation élément.événement = gestionnaire. Cette méthode a l'avantage de pouvoir s'ajouter à des gestionnaires d'événements déjà déclarés sur le même élément, sans les annuler (mais ne s'applique pas à window.onload). Voici un exemple pour illustrer ce principe qui se réfère au click sur un bouton :

<button id="myBtn">Button</button>
<script>
var myBtn = document.getElementById("myBtn");

//1. Utilisation de onclick
myBtn.onclick = function () {
  console.log("Événement 1");
}
myBtn.onclick = function () {
  console.log("Événement 2");
}

//-> Si on click sur myBtn on verra dans la console seulement "Événement 2";

//2. Utilisation de addEventListener
myBtn.addEventListener("click", function () {
  console.log("Événement 1");
});
myBtn.addEventListener("click", function () {
  console.log("Événement 2");
});

//-> Si on click sur myBtn, cette fois-ci, on verra dans la console les deux messages.
</script>

Voici un exemple avec des commentaire pour résumer les différentes utilisation des événements lié à la souris :

<!doctype html>
<html>
<head>
    <meta charset="UTF-8">
    <title>JavaScript - événements liés à la souris</title>
</head>
<body>
  <h1>JavaScript - événements liés à la souris</h1>
  <button id="mon-bouton">Cliquez ici</button>
  <span id="feedback"></span>
  <script>
   //Déclarer une fonction en cas d'événement click
   function showFeedbackClick() {
     document.getElementById("feedback").innerHTML = "J'ai cliqué sur le bouton";
   }

   //Définir une fonction en cas d'événement mouseover
   function showFeedbackOver() {
     document.getElementById("feedback").innerHTML = "La souris se trouve sur le bouton";
   }

   //Identifier le bouton dans le DOM
   var monBouton = document.getElementById("mon-bouton");

   //Trois manières différentes d'associer une fonction à un événement :
   //1. Événement click avec association d'une fonction, sans ()!
   monBouton.onclick = showFeedbackClick
   //2. Événement mouseover avec méthode addEventListener();
   monBouton.addEventListener("mouseover", showFeedbackOver);
   //3. Événement mouseout avec fonction anonyme
   monBouton.onmouseout = function() {
     document.getElementById("feedback").innerHTML = "La souris n'est plus sur le bouton";
   }
  </script>
</body>
</html>

Tester cet exemple

Pour annuler un gestionnaire d'événement il suffit de le rédéclarer null sa propriété d'événement (e.g. mon-élément.mon-événement = null) ou d'utiliser la méthode élément.removeEventListener().

Il existe une méthode plus souple pour définir un gestionnaire d'événnement et que l'on retrouve aussi dans ActionScript.

Dans l'exemple suivant,la fonction start() sera exécutée dès que la page charge, ceci à cause de l'instruction window.onload = start; qui associe à l'événment "onload" le nom d'une fonction qu'il faut exécuter. Rien de neuf là. Par contre la gestion du 2ème événement se fait différemment.

<!DOCTYPE html>
<html>
   <head>
      <title>Event handling</title>
      <script type = "text/javascript">
         window.onload = start;
         // var my_para_button  ="";

	 function start()  {
	   // put an event handler on the div box
	   var my_para_button = document.getElementById("box");
	   my_para_button = addEventListener("click", modifyText);
         }

	 function modifyText() {
	   // get the box
	   var my_content = document.getElementById("content");
	   my_content.innerHTML = "That was so good";
	 }
      </script>
   </head>
   <body>
      <div id="box">
         <p style="background-color:yellow" id="content">CLICK ME !</p>
      </div>
   </body>
</html>

Source: http://tecfa.unige.ch/guides/js/ex-intro/event-handler.html

La fonction start ajoute un gestionnaire d’événement au bouton my_para_button en utilisant la méthode addEventListener ("click", modifyText); . Le premier argument, "click", identifie le type d’événement, et le deuxième donne le nom de la fonction.

L'élément this dans le DOM

Lorsqu'une fonction est associée à un élément du DOM, cet élément est disponible à l'intérieur de la fonction elle-même à travers l'élément this. Ceci permet de ne pas avoir à identifier à nouveau l'élément dans le DOM. Voici un exemple qui modifie le label d'un bouton et le désactive après le click :

<!doctype html>
<html>
<head>
    <meta charset="UTF-8">
    <title>JavaScript - this</title>
</head>
<body>
  <h1>JavaScript - this</h1>
  <button id="mon-bouton">Cliquez ici</button>
  <script>
    var monBouton = document.getElementById("mon-bouton");
    monBouton.onclick = function() {
      //Changer le label du bouton
      this.innerHTML = "J'ai cliquez sur le bouton";
      //Désactiver le bouton
      this.disabled = "disabled";
    } 
  </script>
</body>
</html>

L'élément this peut être très utile lorsqu'on genère plusieurs éléments dynamiquement pour associer un comportement à chaque élément. Voici un exemple similaire au précédent, mais dans lequel 5 boutons sont créés avec la fonction document.createElement("button"). Chaque bouton créé est associé ensuite à un événement de type onclick, à l'intérieur du quel on fait référence au bouton avec l'élément this :

var list = document.getElementById("btnList");
for(var i = 1; i <= 5; i++) {
  var btn = document.createElement("button");
  btn.innerText = "Cliquez sur le bouton " + i;
  btn.onclick = function () {
    this.innerText = "J'ai cliqué sur ce bouton";
    this.disabled = "disabled";
  }
  list.appendChild(btn);
}

Tester cet exemple et l'exemple précédent

JavaScript et CSS

Utiliser les propriétés de style

Javascript permet de modifier non seulement la structure du DOM, mais également les propriétés de style des éléments. Il est possible de modifier toutes les déclarations de style disponible dans un fichier CSS à travers la notation :

élément.style.propriété = "nouvelle valeur";

Par exemple le code suivant modifie la couleur du texte d'un élément du DOM avec id="mon-paragraphe" :

document.getElementById("mon-paragraphe").style.color = "#F00";

Les changements de style peuvent être appliqués à tout moment dans le code et être donc associés par exemple à des événements (voir plus haut dans la page).

Utiliser les classes

JavaScript permet également de manipuler les noms de class des élément. La manière plus simple consiste à utiliser la propriété className pour lire ou définir la class d'un élément :

//Lire
var maClasse = élément.className; // --> e.g. active
//Définir
élément.className = 'active'

Il faut noter que la propriété className se réfère à tout le l'attribut HTML. Voici un élément HTML qui a plusieurs classes :

<div id="myDiv" class="class1 class2 class3">Mon div</div>

Et voici le résultats de quelques opérations avec JavaScript

var myDiv = document.getElementById("myDiv");
var classes = myDiv.className; // --> class1 class2 class3
//Ajouter une quatrième class
myDiv.className = classes + " class4"; // --> class1 class2 class4 class3
//Remplacer avec une seule class
myDiv.className = "class99"; --> class99

Pour faciliter la gestion de plusieurs classes sur le même élément, JavaScript met à disposition la propriété classList qui possède plusieurs méthodes (voir la liste complète) parmi lesquelles on trouve :

  • élément.classList.add(class, [class]) : permet d'ajouter une ou plusieurs nouvelles classes à l'élément
  • élément.classList.remove(class, [class]) : permet d'enlever une ou plusieurs classes à l'élément

Les deux codes suivants sont donc équivalents :

var myDiv = document.getElementById("myDiv");

//Avec className
var classes = myDiv.className; // --> class1 class2 class3
myDiv.className = classes + " class4"; // --> class1 class2 class3 class4

//Avec classList
myDiv.classList.add("class4"); // --> class1 class2 class3 class4

Une autre méthode utile associée à la propriété classList est la méthode toggle() qui :

  1. Ajoute une classe si la classe n'est pas associée à l'élément
  2. Enlève une classe si la classe est déjà associée à l'élément

Tester un exemple

JavaScript et les formulaires

Même si JavaScript ne se limite plus simplement à cette tâche, la manipulation des formulaires et des éléments des formulaires (e.g. champs de texte, etc.) reste une fonctionnalité très utilisé (et utile). JavaScript peut en effet identifier le contenu des éléments des formulaires et utiliser se contenu dans sa logique de programmation pour apporter des changements à la page. Par exemple la propriété .value permet d'identifier le contenu d'un champ de texte :

var maValeur = document.getElementById("mon-champ-de-texte").value;

Cette notation, comme toute propriété, peut être utilisé aussi pour modifier le contenu d'un champ.

window.onload = function() {
    document.getElementById("mon-champ-de-texte").value = "Nouvelle valeur";
}

Voici un exemple qui utilise l'événement onchange pour suggérer une valeur combiné du prénom et nom d'une personne. Si le champ complet est modifié, néanmoins, aucune suggestion ne sera plus faite.

<!doctype html>
<html>
<head>
    <meta charset="UTF-8">
    <title>JavaScript - formulaires</title>
</head>
<body>
<h1>JavaScript - formulaires</h1>
Prénom : <input type="text" id="prenom"><br>
Nom : <input type="text" id="nom"><br>
Nom complet : <input type="text" id="nom-complet"><br>
<script>
  var prenom = document.getElementById("prenom");
  var nom = document.getElementById("nom");
  var nomComplet = document.getElementById("nom-complet");
  function suggererNomComplet() {
    nomComplet.value = nom.value + ", " + prenom.value;
  }
  prenom.onchange = suggererNomComplet;
  nom.onchange = suggererNomComplet;
  nomComplet.onchange = function() {
    prenom.onchange = null;
    nom.onchange = null;
  }
</script>
</body>
</html>

Tester cet exemple

Validation des formulaires

Un autre cadre d'utilisation de JavaScript concerne la validation des formulaires avant qu'ils soient soumis au serveur (i.e. avec actualisation de la page). Cette fonction est désormais partiellement prise en charge par les attributs HTML5 tels que "required", mais il y néanmoins des validations plus complexes qui nécessitent du codage JavaScript.

Dans la structure du DOM, JavaScript peut identifier des champs d'un formulaire de plusieurs manières. On peut utiliser la méthode getElementById() et attribuer à chaque champ un id univoque, ce qui est probablement la manière plus sûre. Si non, JavaScript identifie les formulaires et ses champs à travers un Array qui se construit sur l'attribut name du formulaire et des champs :

 <form name="mon-formulaire">
     <input type="texte" name="mon-champ1">
     <input type="texte" name="mon-champ2">
 </form>

Le form peut être identifié à travers la notation document.forms['mon-formulaire'] tandis que les champs respectivement avec :

  • document.forms['mon-formulaire']['mon-champ1']
  • document.forms['mon-formulaire']['mon-champ2'].

Il est également possible d'utiliser la notation "par point" au lieu des parenthèses carrées si le nom du champ respecte la notation correcte pour les variables JavaScript.

Voici un simple exemple de validation pour montrer brièvement le mécanisme. Le code JavaScript contrôle que le champ email ne soit pas vide et que les conditions ont été acceptées à travers le checkbox.

<!doctype html>
<html>
<head>
    <meta charset="UTF-8">
    <title>JavaScript - formulaires</title>
</head>
<body>
<h1>JavaScript - formulaires</h1>
<form name="mon-formulaire">
  Email : <input name="email" type="text"><br>
  <input type="checkbox" name="conditions"> J'accepte les conditions d'inscription<br>
  <input type="submit" value="Envoyer">
</form>
<script>
  var monForm = document.forms["mon-formulaire"];
  var monEmail = monForm["email"];
  var mesConditions = monForm["conditions"];
  monForm.onsubmit = function() { 
    if (monEmail.value !== "" && mesConditions.checked) {
      //Le formulaire sera soumis au serveur et la page actualisée
      return true; 
    } else {
      window.alert("Vous devez insérer votre email et accepter les conditions");
      //Le retour false fait ainsi que le formualire ne soit pas soumis et la page pas actualisée
      return false;
    }
  }
</script>
</body>
</html>

La sécurité avec JavaScript

La sécurité en JavaScript n'est pas à négliger car de nombreux exploits existent et sont assez facilement mis en place. Avant de commencer à lire ce qui suit, il est important de savoir que le JavaScript est interprété du coté de la machine du client (et non pas du coté du serveur).

Pourquoi il ne faut pas faire confiance à Javascript si vous êtes propriétaire d’un site web

Pour comprendre il suffit de regarder cet exemple qui peut être trouvé sur le site de certains novices.

Exemple :

  function Login(){
            var password=document.login.password.value;
            if (password=="kztYq8") {
                window.location="bravo.htm";
            }
            else
            {
                window.location="dommage.htm";
            }
        }

Vous l'aurez compris, le mot de passe est défini en clair dans le code source de la page. Tout le monde y a accès. L'URL censée être protégée par le mot de passe est aussi disponible et accessible sans le mot de passe! Ayez toujours en tête que ce que vous écrivez en javascript est accessible à tout le monde.

Vérifier du côté client et du côté serveur

Ce qu'on a vérifié du coté client avec le JavaScript n'est pas fiable et doit être revérifié du coté serveur (avec du PHP par exemple). En effet, en désactivant simplement le JavaScript, on peut passer outre les contrôles d'un formulaire.

Attaques de Cross-site scripting (XSS)

Lors de la création d'une application ou d'un site avec JavaScript, il faut savoir que les attaques XSS existent. Elles sont encore couramment utilisées. En résumé, l'attaque consiste à injecter des scripts dans la réponse d'une application, ce qui permet de récupérer les données sensibles de l'application et de les envoyer sur le serveur de la personne qui est à l'origine de l'attaque. Il existe deux types d'attaque XSS.

La reflectected XSS (non permanente) : L'attaquant injecte des scripts dans une application web pour que ceux-ci soient exécutés du coté client. L'attaque n'est pas stockée dans l'application et laisse aucune trace sur le serveur. Pour exploiter cette faille (XSS), l'ingénierie sociale doit être utilisée afin de tromper la "future" victime. L'attaquant va fournir une URL piégée à sa victime (via mail par exemple), lorsque la victime clique sur l'URL piégée, une requête contenant du code malicieux (scripts) est envoyé vers le serveur (officiel). Le code malveillant va alors s'exécuter sur la page renvoyé par le serveur (officiel), ce qui donne à l'attaquant le contrôle dessus. Celui-ci pourra ensuite à partir de l'application récupérer des données sur la victime comme par exemple sa session ou ses cookies et les recevoir directement son serveur. Cela lui permettra de réaliser des actions au nom de l'utilisateur ou de lui voler des informations privées.

Exemple vidéo (anglais) : ICI

La persistent XSS (permanente) : Contrairement au premier type d'attaque, celle-ci consiste à injecter le code malicieux directement dans le système de stockage de l'application Web. Pour que la faille puisse être exploitée, l'application doit générer ses réponses via ces données stockées. Elle est souvent utilisé sur des forums qui sont mal sécurisés. Ceux-ci stockent les messages des utilisateurs dans des bases de donnée. Si un message contient un code malicieux, à chaque fois qu'un utilisateur affichera la page du forum contenant le message qui contient le code malicieux, celui-ci sera exécuté. Cette attaque est donc beaucoup plus dévastatrice puisqu'elle touche potentiellement tous les utilisateurs.

Exemple vidéo (anglais) : ICI

Comment se protéger contre les attaques XSS

Il existe plusieurs moyens de se protéger, la NSA a d'ailleurs rédigé un bon document à ce propos.

Afin d'éviter que des personnes malveillantes puissent injecter du code malveillant, les administrateurs réseaux doivent traiter les informations que les personnes envoient une fois qu'elles sont parvenues au serveur et les retraiter lors de leur envoi au navigateur. Des fonctions PHP existent afin de traiter les données envoyées via JavaScript comme "htmlentities" qui convertit tous les caractères éligibles en entités HTML et strip_tags qui supprime les balises HTML et PHP d'une chaîne. L'une dans l'autre permet déjà une protection de base efficace (mais pas infaillible) contre ce genre d'attaque qui exploite le JavaScript. Des mesures supplémentaires peuvent être mises en place comme l'utilisation de pare-feux applicatifs qui détectent les informations suspectes envoyées au serveur. Du coté des utilisateurs, il ne faut jamais cliquer sur un lien dont la provenance est douteuse et toujours accéder aux sites via l'URL officielle. Il peuvent aussi utiliser des extensions comme par exemple "NoScript" sur Firefox qui offre une bonne protection de base contre ce genre de vulnérabilités.

Références