Fork me on GitHub

JavaScript et le DOM

JavaScript

JavaScript est un langage de scripting interprété, dynamique, faiblement typé, basé sur les prototypes qui supporte les styles de programmation à objets, fonctionnel et impératif.

Interprété : le code est distribué au format source et interprété à la volée.

Dynamiquement typé : les variables peuvent changer de type pendant l’exécution.

Faiblement typé : des variables avec types différent peuvent être combinées sans conversions explicites.

Basé sur les prototypes : il n’y a pas de distinction entre classes et objets : tout est objet.

Fonctionnel: les fonctions sont des objets de première classe.

JavaScript n’est pas Java. Il est bien plus proche de Python ou Ruby.

Hello world

Vieux style

Tester (marche seulement dans un browser)

alert('Hello world');

Nouveau style

Tester (Firefox : Shift+Ctrl+K, Chrome : F12)

console.log('Hello world!');

Marche aussi hors du browser, par ex., dans Node.js.

La syntaxe JavaScript

if (x == 1) {
    ...
} else if (x == 2) {
    ...
} else {
    ...
}
switch (2+x) {
case 4:
    ...
	break;
case 5+1:
    ...
	break;
default:
    ...
}
for ( var i = 0 ; i < 10 ; i++ ) {
    ...
}
for ( var x in obj ) {
    ...
}
while (condition) {
    ...
}
do {
    ...
} while (condition);
try {
    ...
} catch (e) {
    if (e instanceof SyntaxError) {
        ...
    } else {
        ...
    }
} finally {
    ...
}

Note : il n’y a pas encore de standard pour capturer des exceptions d’un type spécifique.

Variables

Les variables doivent être déclarées !

var a = 0;
a += 1;

Les variables non déclarées ont portée globale.

function setA() { a = 1; }
setA();
console.log(a);  // affiche 1

À utiliser avec parcimonie.

Les variables sont typées dynamiquement

var a = 1;
a = 'quelque chose';

Constantes

Constantes prédéfinies : undefined, NaN, Infinity.

Utilisation de undefined

function bon(x, y) {
	// teste si l'utilisateur a passé
	// une valeur pour y 
	if (undefined === y)
		...
}
function mauvais(x, y) {
	if (undefined == y)
		// s'exécute même si y vaut 0 ou ''
		...
}

Quelques opérateurs

Comparaison faible

var x = 2;
x == '2';     // true

Comparison forte

var x = 2;
x === '2';    // false

Existence d’attribut (teste si une propriété est définie dans un object)

if ('property' in obj) ...;
if ('key' in myarray) ...;     // moins utile

Tableaux

Allocation dynamique

var myarray = ['un', 'deux', 'trois'];
myarray[5] = 'cinq';
myarray.length;                        // donne 6

Tableaux associatifs

var myarray = []
myarray['six'] = 6;

Méthodes prédéfinies

(seulement pour un tableau non associatif)

// donne is 'un+deux+trois'
['un', 'deux', 'trois'].join('+')

Fonctions

Syntaxe simple

(les arguments n’ont pas besoin du mot clef var)

function incr(a) {
    return a+1;
}

Les fonctions sont des objets de première classe

function apply(f, x) {
    return f(x);
}

apply(incr, 4);          // donne 5

Fonctions anonymes

myFun = function () {
    ...
}

Fonctions imbriquées (et fermetures)

function counter() {
    var c = 0;
    return function(step) {
        return c += step;
    }
}

var cnt = counter();
[cnt(1), cnt(2), cnt(1)]      // donne [1, 3, 4]

Voir http://bonsaiden.github.com/JavaScript-Garden/#function.

Fonctions variadiques

Omettre des arguments

function maybe(x, y) {
    if (undefined === y) 
        return x;
    else
        return x+y;
}

maybe(1);          // donne 1
maybe(1, 2);       // donne 3

Donner plus d’arguments

function prepend(x) {
    var res = []
    for (var a in arguments)
        res.push(x + arguments[a]);
    
    return res
}

// donne ['pre-a', 'pre-bbb', 'pre-c']
prepend('pre-', 'a', 'bbb', 'c');

Objets

Objets anonymes

(similaires aux tableaux associatifs)

var myObj = {
    car: "Peugeot",
    color: "blue"
};

'car' in myObj;              // true
myObj.car == "Peugeot";      // true
myObj['car'] == "Peugeot";   // true

var prop = 'car';
myObj[prop] == "Peugeot";    // true

Les contenus d’un objet peuvent changer dynamiquement

var myObj = {};
myObj.car = "Renault";

Méthodes

var myObj = {
  jour: "5",
  mois: "Janvier",
  annee: "2012",
   
  anglais: enDate,
  
  francais: function() {
    return this.jour  + " " + this.mois + " " + this.annee;
  }
}

function enDate() {
  return this.mois + " "  + this.jour  + ", " + this.annee;
}

myObj.custom = function() {
  return this.annee  + "-" + this.mois + "-" + this.jour;
}

Portée de this (avancé)

Dans une méthode this se réfère à l’objet courant

var myobj = {
	mymethod: function(a, b) {
		console.log(this, a, b);
	}
}
myobj.mymethod(1, 2)             // affiche myobj, 1, 2

pour une fonction, il se réfère à l’objet global (Window dans un browser)

var myfunc = myobj.mymethod
myfunc(1, 2)                     // affiche window, 1, 2

this peut être lié (bound en anglais)

// affichent tous myobj, 1, 2
var myfunc2 = myfunc.bind(myobj);  myfunc2(1, 2);
myfunc.call(myobj, 1, 2);
myfunc.apply(myobj, [1, 2]);

Voir http://bonsaiden.github.io/JavaScript-Garden/#function.this.

Constructeurs

Les constructeurs sont des simples fonctions

function Car(model, color, year) {
    this.model = model;
    this.color = color;
    this.year = year;
    
    this.revision = function() {
        return this.year + 5;
    }
}

var mycar = new Car("Peugeot", "blue", 2010);


// donne 2015
mycar.revision();

Prototypes (avancé)

Les prototypes remplacent l’héritage

function A() { this.one = 1; }

function B() { this.two = 2; }
B.prototype = new A();

var C = new B();
C.one;                         // donne 1
C.two;                         // donne 2

Les prototypes enrichissent les objets

var foo = "bar";
foo.methodeBete;                    // undefined

String.prototype.methodeBete = function() {
	return "bête";
}
foo.methodeBete();                  // donne "bête"

Objets prédéfinis

String, Array, Boolean, Number, Date: les noms disent tout

Math: Fonctions mathématiques (exp, log, etc.)

Math.PI;         // la constante pi
Math.sqrt(16);   // donne 4

RegExp: expressions régulières (syntaxe à la Perl)

var pattern = RegExp("sub", "i");

// pareil que la ligne du dessus
pattern = /sub/i;

// donne true
pattern.test("Substring")

Lectures

JavaScript Éloquent par Marijn Haverbeke
http://fr.eloquentjavascript.net/,
Le guide du MDN
https://developer.mozilla.org/docs/JavaScript/Guide,
Les tutoriels de W3Schools
http://www.w3schools.com/js/,

Plus de références dans la page du cours.

Le DOM

Document Object Model

Qu’est-ce que le DOM ?

  • Une API (des objets JavaScript),
  • À chaque élément d’une page HTML correspond une classe,
  • Toutes les classes héritent de HTMLElement (qui hérite de Node).
  • Un document HTML valide est représenté par un arbre d’objets du DOM.

Comment JavaScript intéragit avec le document ?

  • À travers les méthodes du DOM (ajouter, enlever des éléments, modifier le style, etc.),
  • À travers les gestionnaires d’évènements (actions de la souris, du clavier, etc.).

Les éléments racine

Window

La fenêtre du browser (pas un objet du DOM, à proprement parler)

window.innerHeight + " x " + window.innerWidth

Taille courante :

Document

Le document HTML

document.referrer

Vous avez navigué vers cette page de :

Sélectionner les éléments (browsers modernes)

querySelector renvoie la première balise correspondante au sélecteur CSS

document.querySelector('.start + span')
	.style.backgroundColor = 'red';
document.querySelector('#ilove').querySelector('span')
	.style.backgroundColor = 'blue';

querySelectorAll renvoie la liste des balises

var nodes = document.querySelectorAll('#ilove span');
for (var i = 0 ; i < nodes.length ; i++)
	nodes[i].style.color = 'white';

Exemple (cliquez sur les exemples ci-dessus)

I Love DOM

<div id="ilove">
<span class="start">I </span><span id='L'>L</span>ove DOM
</div>

Autres méthodes

Accès direct (pour les vieux browsers)
getElementById (équivalent à #id),
getElementsByName (équivalent à [name=...]),
getElementsByTagName (équivalent à tag),
getElementsByClassName (équivalent à .class).
Traverser l’arbre
Fils : childNodes, firstChild, lastChild, …
Sœurs : nextSibling, previousSibling,
Parent : parentNode.
Modifier l’arbre
Créer : document.createElement, cloneNode,
Ajouter : appendChild, insertBefore, …
Supprimer : removeChild, …
Remplacer : replaceChild, …

Agir directement sur le HTML : .innerHTML, .outerHTML

node.innerHTML += "<p>Modifier le <em>HTML</em></p>";

Accès aux attributs

<div class="ma-classe" data-ma-donnee="1" title="hello">

Attributs quelconques : getAttribute, setAttribute

element.setAttribute('title', 'hi');

Accès à la classe : className, classList

element.className = "classe1";
element.classList.add("classe2");
element.classList.remove("classe1");

Accès au style : style

element.style.color = 'white'

API dataset

element.dataset['ma-donnee'] = 2;

Événements

Dans le HTML: onload, onclick, onmouseover, onkeypress, ondrag, …

<!-- passer la souris sur ce bloc -->
<div id="mydiv" onmouseover="this.style.opacity='0.4'"
                onmouseout="this.style.opacity='1'">

De JavaScript: meilleur séparation du HTML, à préférer.

document.querySelector('#mydiv').onmouseover =
    function(e) { this.style.opacity = '0.4'; };

De JavaScript: encore mieux, pas de conflicts avec d’autres scripts !

function fade() {
    this.style.opacity = '0.4';
}

document.querySelector('#mydiv')
	.addEventListener('mouseover', fade, false);

L’objet evenement

element.onclick = function (event) {
	console.log(event);
}

Le paramètre event du gestionnaire d’événements contient plusieurs champs importants

  • currentTarget : élément à qui le gestionnaire est associé ;
  • target : élément qui a déclanché l’événement (peut être un fils de currentTarget) ;
  • type : type de l’événement (souris, clavier, etc.) ;
  • which : quelle touche a été appuyée ;

Et des méthodes

  • stopPropagation : arrête la propagation de l’événement aux parents ;
  • preventDefault : évite l’action par défaut associée à l’évènement (par ex., arrête la soumission d’un formulaire).

Voir https://developer.mozilla.org/docs/Web/API/Event

Plus sur le DOM

Plus de lecture

Le tutoriel de W3Schools
http://www.w3schools.com/jsref/.
La référence du DOM implanté par Firefox
https://developer.mozilla.org/docs/DOM/DOM_Reference.
Plus de ressources, par le MDN
https://developer.mozilla.org/DOM

En pratique

  • Utilisez JQuery pour la production.

Plus d’outils (DOM inspectors)

  • Dans Firefox (Shift+Ctrl+C) et Chrome (F12) : dev tools.

Se simplifier la vie (ma polyfill préférée)

Des noms courts : $ et $$

$ = document.querySelector.bind(document);
$$ = document.querySelectorAll.bind(document);

Définis pour tout élément

HTMLElement.prototype.$ =
	HTMLElement.prototype.querySelector;
HTMLElement.prototype.$$ =
	HTMLElement.prototype.querySelectorAll;

Et une façon simple d’itérer sur les listes d’éléments

Nodelist.prototype.forEach = Array.prototype.forEach;

Exemple d’utilisation

$('table').$$('tr').foreach(function(row) {
	console.log(row);
});

Frameworks client

Les frameworks client JavaScript sont des bibliothèques qui étendent JavaScript dans le browser.

Pourquoi ?

  • Remédier aux incompatibilités des browsers ;
  • Simplifier les tâches fréquentes (par ex., utiliser querySelector, parser des données XML ou JSON) ;
  • Enrichir la sémantique de JavaScript (par ex. ajouter forEach aux listes d’éléments du DOM) ;
  • Améliorer l’interface utilisateur (par ex. animations, contrôles avancés).

Ils deviennent indispensables en production, lorsqu’un site doit être largement accessible.

JQuery

JQuery est un framework JavaScript très populaire. Il hérite de concepts provenants de Prototype et Script.aculo.us.

Caractéristiques principales

  • Compatibilité Cross-browser ;
  • Sélecteurs à la querySelector ;
  • Éléments DOM enrichis ;
  • Framework AJAX ;
  • Noyau très compact (seulement 31k);
  • Composants UI modulaires (JQuery UI) ;
  • Architecture à plug-ins.

Documentation : http://docs.jquery.com/,

JQquery UI : http://jqueryui.com/.