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.

_images/client-server.png

Source image http://commons.wikimedia.org/wiki/File:Client-server-model.svg

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

Indication

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.

Indication

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.

Remarque

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) {
    let r = 1;
    for(let i=1; i<=n; i+=1) {
        r *= i;
    }
    return r;
}

Indication

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

Vocabulaire

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 un mot-clé let, const ou var (ce dernier est de moins en moins utilisé). Lorsqu'une variable est déclarée avec le mot-clef const, elle doit être immédiatement initialisée et ne peut être réaffectée.

Indication

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é 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.

Indication

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.

Indication

JSHint détecte toute utilisation de == ou != à condition d'activer le contrôle ainsi :

// jshint eqeqeq:true

Avertissement

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
}

Avertissement

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.

Indication

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)

Avertissement

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.

Indication

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

 1<p>Hello <span onmouseover="f1();">world</span></p>
 2<button onclick="f2();">Click me</button>
 3
 4<script>
 5  function f1() {
 6      console.log('haha, tickles');
 7  }
 8  function f2() {
 9      console.log('click');
10  }
11</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 :

Indication

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

Remarque

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

Indication

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)

Syntaxe

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.

Bonne pratique

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', ...).

Bonne pratique

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.

Indication

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// définition des fonctions f1 et f2, puis...
 2
 3function cree_abonnements() {
 4  document.getElementsByTagName('span')[0]
 5    .addEventListener('mouseover', f1);
 6  document.getElementById('b1')
 7    .addEventListener('click', f2);
 8}
 9
10window.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

Indication

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