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
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
etundefined
.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
É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>
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>
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>
É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 onX
où X
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énementeventname
sur cet élémenttextContent
: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 classecls
.
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);
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'objetwindow
, 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);
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
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.