Introduction au langage§

Rappels§

Architecture Client-Serveur§

  • Ressource: toute unité d’information (document, image, vidéo...) accessible sur le Web
  • Serveur: un ordinateur « contenant » des ressources, toujours connecté à Internet.
  • Client: un ordinateur/smartphone/tablette... utilisé pour afficher des ressources.

Rôles du serveur§

  • Le serveur est garant de l’état des ressources.
  • Il fournit au client une représentation de la ressource
    • soit stockée telle quelle (fichier),
    • soit calculée à la demande (PHP, Java...).

Rôles du client§

  • Afficher la représentation de la ressource.
  • Assurer les interactions avec la ressource :
    • liens vers d’autres ressources,
    • liens internes,
    • autres types d’interactions « internes » (<video>, :hover...).
  • HTML + CSS peuvent être considérés comme
    • un langage de programmation déclaratif,
    • spécialisé dans la description de documents hypermédia,
    • offrant un ensemble limité d’interactions.
  • Javascript complète HTML + CSS
    • avec un langage de programmation généraliste,
    • offrant un spectre beaucoup plus large d’interactions.

Syntaxe§

Inspiration§

  • Comme son nom l’indique, la syntaxe de Javascript est (librement) inspirée de celle de Java (ou du C).
  • La similitude s’arrête là : Javascript n’est pas basé sur Java.

Condition§

if (i < 10) {
    j = j+1;
    k += i;
} else {
    j = 0;
}

Boucles§

while (i < 10) {
    j = j*i;
    i += 1;
}
for(i=0; i<10; i+=1) {
    j = j*i;
}

Exceptions§

if (i < 0) {
    throw new Error("negative value");
}
try {
    i = riskyFunction();
}
catch (err) {
    i = -1;
}

Tableaux§

a = [1,2,3,5,8,13];
for (i=0; i < a.length ; i+=1) {
    console.log(a[i]);
}
// affiche tous les éléments du tableau

Indice

Comme en Python et contrairement à Java, les tableaux en JS peuvent changer de taille (voir leur documentation pour plus de détails)

Avertissement

Contrairement à Python, un tableau vide (de longueur 0) est équivalent à true dans une condition.

Différences§

Il existe cependant des différences importantes que vous devez connaître.

Langage interprété§

  • Javascript est un langage interprété, et n’a donc pas de phase de compilation.
  • Or le compilateur a un rôle important dans la détection d’erreurs, y compris des erreurs non critiques.
  • Il vous est fortement recommandé d’utiliser des outils de vérification de code, tels que JSHint.
  • NB : les IDEs intègrent généralement ce genre d’outil.

Note

JSHint peut être installé sur votre machine, mais peut également être utilisé directement en ligne.

Chaînes de caractères§

  • Contrairement au C ou au Java, Javascript n’a pas de type char.
  • Si txt est une chaîne de catactères, txt[i] retourne également une chaîne de caractères de longueur 1.
  • Les guillemets simples (') ou doubles (") peuvent être utilisés indifféremment pour délimiter les chaînes de caractères.

Note

Ces particularités sont partagées avec d’autres langage dynamiquement typés, comme par exemple Python.

Typage dynamique§

En Java (comme en C), les variables et les fonctions ont un type fixé :

int fact(int n) {
    int r = 1;
    for(int i=1; i<=n; i+=1) {
        r *= i;
    }
    return r;
}

En Javascript (comme en Python), on ne spécifie pas le type des variables ou des fonctions :

function fact(n) {
    var r = 1;
    for(var i=1; i<=n; i+=1) {
        r *= i;
    }
    return r;
}

Indice

Remarquez le mot-clé var devant les premières utilisations des variables r et i.

Note

On parle de typage dynamique, car cela permet à une variable de contenir (par exemple) un entier à un moment, et une chaîne de caractères à un autre moment. De la même manière, une fonction pourra retourner (par exemple) tantôt un flottant, tantôt un entier.

Cette flexibilité est utile dans certains cas, même si bien sûr il ne faut pas l’utiliser pour faire n’importe quoi...

Déclaration des variables locales§

Contrairement aux autres langages dynamiquement typés, Javascript demande que les variables locales soient déclarées, avec le mot-clé var.

Indice

Les paramètres des fonctions font exception à cette règle, puisqu’ils sont déclarés par leur présence dans l’en-tête de la fonction.

Avertissement

Un oubli du mot-clé var est dangereux, car il ne constitue pas une erreur, mais dans ce cas la variable est considérée comme globale, ce qui peut créer des bugs difficiles à détecter, comme le montre cet exemple.

Indice

JSHint détecte ce type d’erreur dans la plupart des cas, à condition d’activer le contrôle ainsi :

// jshint undef:true

Tests d’égalité§

En JS, on teste l’égalité avec l’opérateur ===, et l’inégalité avec l’opérateur !== :

if (i === j  &&  i !== k) // ...

Avertissement

Les opérateurs habituels == et != existent aussi, mais ils ont une sémantique très inhabituelle, et sont donc généralement évités.

Indice

JSHint signale toute utilisation de == ou !=.

Note

En fait, l’opérateur == considère que deux valeurs de types différents sont égales si on peut passer de l’une à l’autre par conversion de type.

Par exemple :

"42" == 42 // est vrai

C’est un problème, car cela conduit à des choses contre-intuitives :

if (a == b  &&  b == c) {
    a == c; // peut être faux
    // par exemple : a = "0", b = 0, c = "" ;
    // en effet, 0 et "" sont tous deux équivalents à false
}

ou encore :

if (a == b) {
    a+1 == b+1; // peut être faux
    // par exemple : a = "42" (a+1 == "421") et b = 42 (b+1 == 43)
}

null et undefined§

  • En Java et en C, il n’existe qu’une seule valeur « nulle ».
  • En JS, il en existe deux : null et undefined.
  • Elles sont utilisées dans des contextes un peu différents; pour l’instant, retenez surtout que les deux existent.

Indice

Les deux sont équivalentes à false dans une condition.

Éléments inexistants§

En Javascript, l’accès à un élément inexistant dans un tableau ou un objet ne déclenche pas d’erreur, mais retourne simplement undefined.

Ceci cause en général une erreur ailleurs dans le code, ce qui le rend plus difficile à déboguer :

let a = ["Alice", "Bob", "Charlie"];
let n = a[5];  // n reçoit undefined
if (n.length > 32) { // erreur : undefined n'a pas de longueur
  // ...
}

À vous de jouer§

  • Documentation
  • Environnement de test
  • Écrivez et testez
    • un programme qui affiche « hello world » dans la console développeur
    • une fonction qui compte le nombre de voyelles dans une chaîne de caractères
    • une fonction qui trouve le plus petit élément d’un tableau
    • une fonction qui calcule la moyenne d’un tableau
    • ...
  • NB : pour afficher dans la console développeur, utilisez console.log(message)

Note

Comme son nom l’indique, la console développeur est déstinée au développeur, pas à l’utilisateur final (qui n’ouvre pas la console). L’utilisation de console.log doit donc être réservée aux messages de debug.

Notion d’événement HTML§

Programmation événementielle§

  • En programmation impérative classique, la fonction principale (main) décrit dans quel ordre les différentes fonctions du programme doivent s’exécuter.
  • En programmation événementielle, on « abonne » chaque fonction à un (ou plusieurs) événement(s).
  • La fonction s’exécute lorsqu’un événement auquel elle est abonnée se produit.
  • Les événement sont (souvent) liés aux interactions de l’utilisateur avec l’application.

Intégration directe au HTML§

<p>Hello <span onmouseover="console.log('haha, tickles');">world</span></p>
<button onclick="console.log('click');">Click me</button>

Essayez cet exemple.

Indice

Pour voir ce qui s’affiche sur la console, pressez CTRL+SHIFT+J (sous Chrome) ou CTRL+SHIFT+K (sous Firefox).

Définition des fonctions dans une balise script§

<p>Hello <span onmouseover="f1();">world</span></p>
<button onclick="f2();">Click me</button>

<script>
  function f1() {
      console.log('haha, tickles');
  }
  function f2() {
      console.log('click');
  }
</script>

Essayez cet exemple.

Définition des fonctions dans un script externe§

<p>Hello <span onmouseover="f1();">world</span></p>
<button onclick="f2();">Click me</button>

<script src="s1_script_externe.js"></script>

Essayez cet exemple, ou modifiez-le.

Événements§

Le standard HTML5 définit un large éventail d’événements que le code Javascript peut intercepter :

Indice

Dans le code HTML, les attributs correspondants ont toujours la forme onXX est le nom de l’événement.

Manipulation du HTML§

L’objet document§

La variable globale document contient un objet représentant le document HTML. Elle permet d’accéder aux éléments du document :

getElementsByTagName(tagname):
retourne un tableau des éléments définis par une balise tagname
getElementById(id):
retourne l’élément ayant pour identifiant id
querySelector(cssSelector):
retourne le premier élément vérifiant un sélecteur CSS
querySelectorAll(cssSelector):
retourne tous les élément vérifiant un sélecteur CSS

Note

On définira la notion d’élément plus en détail la semaine suivante, dans la partie sur L’arbre DOM.

Note

Il est plus efficace d’utiliser les méthodes getElement* que d’utiliser querySelector* avec les sélecteurs correspondants (tagname ou #identifier).

Attributs et méthodes d’un élément§

addEventListener(eventname, func):
abonne func à l’événement eventname sur cet élément
textContent:
permet de consulter et modifier le contenu textuel de l’élément
style:

permet de consulter et modifier l’attribut style de l’élément, sous forme d’un objet ayant un attribut pour chaque propriété CSS. (e.g. e.style.fontSize pour la propriété font-size)

Note

Pour faciliter l’utilisation en Javascript, la typographie des attributs de style n’est pas la même que celle des propriétés CSS correspondantes. Les tirets (-) sont remplacés par une mise en majuscule de la lettre suivante (CamelCase).

classList:

permet de consulter et modifier l’attribut class de l’élément, grâce aux méthodes suivantes :

  • add(cls): ajoute la classe cls a l’élément.
  • remove(cls): retire la classe cls a l’élément.
  • contains(cls): indique si l’élément possède actuellement la classe cls.
  • toggle(cls): inverse l’état de la classe cls (présente/absente) sur l’élément.

Note

Comme en HTML+CSS, il est préférable de spécifier la mise en forme à l’aide de classes dans le CSS, et de modifier ces classes dans le code Javascript, plutôt que la spécifier directement dans le code Javascript à travers l’attribut style.

Les éléments possèdent de nombreux autres attributs; en particulier, chaque attribut HTML a une contrepartie en Javascript.

On peut notamment citer :

  • href (pour les <a>)
  • src (pour les <img>)
  • value (pour les <input>)
  • disabled (pour tous les éléments de formulaire)
  • checked (pour les cases à cocher)
  • etc...

Expérimentez§

... sur cet exemple.

Définition des fonctions et des abonnements dans un script externe§

<p>Hello <span>world</span></p>
<button id="b1">Click me</button>

<script src="s1_script_externe.js"></script>
// définition de f1 et f2 comme précédemment, puis...

document.getElementsByTagName('span')[0]
  .addEventListener('mouseover', f1);

document.getElementById('b1')
  .addEventListener('click', f2);

Voir et modifier cet exemple.

Avertissement

Le nom de l’événement, passé à addEventListener, ne doit pas comporter le préfixe on. On écrira donc addEventListener('click', ...), et non addEventListener('onclick', ...).

Note

Ceci est la bonne manière d’abonner une (ou plusieurs) fonctions(s) à des événements, notamment parce qu’elle permet de séparer l’aspect structurel (HTML) de l’aspect dynamique (Javascript).

Les manières présentées précédemment vous ont été présentées

  • pour des raisons pédagogiques (elles permettent de présenter plus simplement la notion d’événement), et
  • pour des raisons historiques (vous rencontrerez peut-être du code ancien qui les utilise).

Mais il vous est fortement déconseillé de les utiliser dans du code que vous écrivez vous-mêmes.

Événement de chargement de la page§

  • On ne peut pas garantir que la page HTML sera totalement construite avant l’exécution du code Javascript.
  • Par conséquent, les appels à getElement* peuvent échouer.
  • Pour créer les abonnements, il faut donc attendre l’événement indiquant la construction complète de l’arbre HTML.
  • Cet événement se nomme load, et il est accessible sur l’objet window, qui représente la fenêtre du navigateur.

Note

Contrairement aux éléments HTML, l’objet window existe forcément dès l’exécution du Javascript, donc on peut sans risque s’abonner à ses événements.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// définition des fonctions f1 et f2, puis...

function cree_abonnements() {
  document.getElementsByTagName('span')[0]
    .addEventListener('mouseover', f1);
  document.getElementById('b1')
    .addEventListener('click', f2);
}

window.addEventListener("load", cree_abonnements);

Voir et modifier cet exemple.

TP : Formulaires avec différents contrôles§

Sujet§

  • Créez un formulaire contenant les champs suivants : Prénom, Nom, Age, Identifant, Mot de passe (2 fois), et une case à cocher « J’accepte les CGU ».
  • Le bouton de soumission est grisé, et ne s’active que lorsque les conditions ci-dessous sont toutes satisfaites :
    • l’âge est un entier supérieur ou égal à 18;
    • l’identifiant est composé de moins de 12 caractères, seulement des lettres;
    • le mot de passe est suffisamment « fort » (cf. ci-dessous);
    • le deuxième mot de passe est identique au premier;
    • les CGU ont été acceptées.
  • La force du mot de passe doit s’afficher (en %) à côté du mot de passe; les 5 critères suivants y contribuent à 20% chacun :
    • il doit faire au moins 8 caractères,
    • il doit contenir au moins une lettre minuscule,
    • il doit contenir au moins une lettre majuscule,
    • il doit contenir au moins un chiffre,
    • il doit contenir au moins un caractère qui ne soit ni une lettre, ni un chiffre.
  • Par ailleurs, le formulaire doit indiquer le plus explicitement possible à l’utilisateur ce qu’on attend de lui (textes d’aide, mise en évidence...).

NB : Vous pourriez trouver utile l’annexe ci-après.

Liens utiles§

Liens utiles

Annexe : les expressions régulières§

Définition§

Une expression régulière (ou regexp) décrit dans une syntaxe spécialisée une famille de chaînes de caractères.

Par exemple :

  • [a-z]{1,5} : un mot de 1 à 5 lettres
  • \d{2}/\d{2}/\d{4} : une date (jj/mm/aaaa)
  • [a-z]+@[a-z]+(\.[a-z]+)* : une adresse e-mail

Indice

Les expressions régulières sont utilisables dans tous les langages de programmation, mais elles sont particulièrement bien intégrées à Javascript.

Pour en savoir plus§