Tour d'horizon JavaScript

Grégory PAUL • 2009

Valid XHTML 1.0 Strict
Creative Commons License

http://javascript.training.free.fr

JavaScript

Notes

L'icône suivant [JavaScript executable], qui accompagne le code JavaScript de cette présentation, indique que ce dernier est exécutable depuis votre barre d'adresse (en tapant : "javascript:" + code JavaScript) ou depuis un interpréteur plus évolué comme par exemple Firebug.

Essayez avec cet exemple :

alert("Prêt pour du JavaScript ?");

N'hésitez pas à en abuser ! :D

Sommaire

  1. JavaScript : état des lieux
  2. Versions
  3. Usages
  4. Orienté objet
  5. Typage dynamique
  6. Evaluation à l'éxecution
  7. Les Fonctions (internes, anonymes, closures)
  8. Tableaux
  9. Orienté objet à Prototype
  10. DOM
  11. Evénements
  12. Ajax
  13. JSON
  14. E4X
  15. Librairies
  16. JavaScript dans le navigateur
  17. Meilleures pratiques
  18. Securité
  19. Outils (développement, débogage)
  20. Références
  21. Questions et réponses
  22. ROTI

JavaScript : état des lieux

Versions

Version Release date Equivalent to Netscape Navigator Mozilla Firefox Internet Explorer Opera Safari
1.0 03/1996 2.0 3.0
1.1 08/1996 3.0
1.2 06/1997 4.0-4.05
1.3 10/1998 ECMA-262 1st edition & 2nd edition 4.06-4.7x 4.0
1.4 Netscape Server
1.5 11/2000 ECMA-262 3rd edition 6.0 1.0 5.5 (JScript 5.5), 6 (JScript 5.6), 7 (JScript 5.7), 8 (JScript 6) 6.0, 7.0, 8.0, 9.0
1.6 11/2005 1.5 + Array extras, Array and String generics, E4X 1.5 3.x
1.7 10/2006 1.6 + Pythonic generators, Iterators, let 2.0
1.8 06/2008 1.7 + Generator expressions, Expression closures 3.0
1.9 1.8 + New Features 3.1
2.0 ECMA-262 4th edition, entre Java & Python : interface, classe, namespace, package, annotations...

Usages

Omniprésent sur le web (1 page sur 2) mais attention aux abus !

Usages

JavaScript peut apporter un confort d'utilisation mais une application web doit être capable de fonctionner sans !

JavaScript activation in Firefox
désactivation, support limité sur certains terminaux et robots !

Pour en savoir plus :

Le language



Spécificités du language

Orienté objet

var car = new Object(); ou var car = {};
Les objets sont des tableaux associatifs :
car.wheels = 4; car.start = function() { alert("vroom"); }; ou car['wheels'] = 4; car['start'] = function() { alert('vroom'); };
var eiffel_tower = { height: 352, weight: 4567, stand: function() { alert("I haven't moved"); } };

Les propriétés et méthodes peuvent être ajoutées, modifiées et supprimées à l'exécution.

Orienté objet

Différents objets natifs sont présent sur chaque page : window, document, window.navigator, etc

Syntaxe for...in pour parcourir les propriétés et méthodes d'un objet :

var things = ""; for (thing in window) { things += thing + "\n"; } alert(things);

things fait maintenant partie de l'objet window (périmètre par défaut)

Les méthodes de "base" (window.alert, window.open,...) font partie de l'objet window

Typage dynamique

var variable = 1; variable = 3.14; variable = "Maintenant une chaîne"; variable = true; variable = {}; variable = function() {}; variable = []; variable = new Date(); variable = /(\w+)\s(\w+)/; variable = null; variable = undefined; number number (float) string boolean object function (object) object (array) object (date) object (regular expression) object ! undefined

Pour voir le type : typeof

alert(typeof new Date()); alert(typeof []); alert(typeof null); alert(typeof undefined);

Typage dynamique

Duck Typing

If it walks like a duck and quacks like a duck, I would call it a duck.James Whitcomb Riley

var donald_duck = { quack: function() { return "quack"; } }; var chasseur = { quack: function() { return "imitation de quack"; } }; function dans_la_foret(etre_vivant) { alert( etre_vivant.quack()); }; dans_la_foret(donald_duck); dans_la_foret(chasseur);

Gardons en tête qu'il n'y a pas de classe, ni d'interface !

Evaluation à l'éxecution

var code = "alert('hey you');"; eval(code);

Quelque chose de plus intéressant :

var xhr = new XMLHttpRequest(); xhr.open("GET","js/eval-example.js", false); xhr.send(null); if (xhr.status == 0) { eval(xhr.responseText); };

Fonctions "first-class"

JavaScript is said to support first-class functions (or function literal)...

function calculateAndShowFor5(functionToApply) { alert(functionToApply(5)) }; function squareComputation(a) { return a*a; } calculateAndShowFor5(squareComputation);

Pour voir le code d'une fonction :

alert(calculateAndShowFor5);
alert(window.open);

Fonctions anonymes

function calculateAndShowFor5(functionToApply) { alert(functionToApply(5)) }; calculateAndShowFor5(function(value) { return value + value; });

Fonctions internes

function add() { var initialValue = 1; function addOne() { return initialValue + 1; } return addOne(); } alert(add()); alert(add);

~private en Java

Closures

Il s'agit de la possibilité, pour une expression, d'accéder à des variables qui ne devraient plus être à sa portée :

function makeAdder(a) { return function(b) { return a + b; } } var f1 = makeAdder(5); alert(f1); alert(f1(6)); var f2 = makeAdder(20); alert(f2(7));

Fuites mémoires ! (surtout si références circulaires)

Tableaux

var a = new Array(); a[0] = "dog"; a[a.length] = "cat"; a.push("hen"); alert(a.length);
var a = ["dog", "cat", "hen"]; alert(a.length);
var a = ["dog", "cat", "hen"]; a[100] = "fox"; alert("a.length:" + a.length + " and a[50]:" + a[50]);
var a = ["dog", "cat", "hen"]; for(var index in a) alert(a[index]);

Orienté objet à Prototype

function Person(first, last) { this.first = first; this.last = last; this.fullName = function() { return this.first + ' ' + this.last; }; } var peter = new Person("Peter-Paul", "Koch"); alert(peter.fullName());

Nouvelle instance de la fonction fullName pour chaque objet

Orienté objet à Prototype

function personFullName() { return this.first + ' ' + this.last; } function Person(first, last) { this.first = first; this.last = last; this.fullName = personFullName; } var peter = new Person("Peter-Paul", "Koch"); alert(peter.fullName());

Mieux mais pas encore ça

Orienté objet à Prototype

function Person(first, last) { this.first = first; this.last = last; }; Person.prototype.fullName = function() { return this.first + ' ' + this.last; }; var peter = new Person("Peter-Paul", "Koch"); alert(peter.fullName());

Et voilà

alert(peter.fullNameReversed()); Error: fullNameReversed is not a function Person.prototype.fullNameReversed = function() { return this.last + ', ' + this.first; }; alert(peter.fullNameReversed());

Orienté objet à Prototype

Surcharge sur un objet :

var peter = new Person("Peter-Paul", "Koch"); var john = new Person("John", "Resig"); peter.writeBook = function() { return this.first + " wrote a book"; }; alert(peter.writeBook()); alert(john.writeBook()); Error: writeBook is not a function

Orienté objet à Prototype

var name = "Dean Edwards"; alert(name.reverse()); Error: reverse is not a function
String.prototype.reverse = function() { var r = ""; for (var i = this.length - 1; i >= 0; i--) { r += this[i]; } return r; }; alert(name.reverse()); alert("hello".reverse());

De nombreuses librairies surchargent les types de base de la sorte !

DOM ou Document Object Model

HTML DOM structure

DOM structure on Firebug

DOM ou Document Object Model

Historique

Etat des lieux

Depuis 2005, le DOM est assez bien supporté dans les navigateurs : IE 6 et +, Firefox, Safari, Opera, etc

Evénements

4 façons de faire : "inline", traditionnel, W3C et Microsoft

1. Inline

<a href="somewhere.html" onClick="alert('click !')">
Comportement/JavaScript mélangé à la structure/HTML : maintenabilité

2. Traditionnel

function doSomething() { alert("Click"); }; document.body.onclick = doSomething;
Pas de parenthèses !
Un événement ne contient qu'une seule fonction

Evénements

3. W3C - DOM Level 3 Event specification

Supporté par Mozilla, Opera, Safari, Chrome et Konqueror

document.body.addEventListener('click',doSomething,false); document.body.addEventListener('click',doSomethingElse,false); document.body.removeEventListener('click',doSomething,false)
element.addEventListener('click',function() { this.style.color = 'red'; }, false)

3 arguments :

Evénements

Capturing

               | |
---------------| |-----------------
| <p>          | |                |
|   -----------| |-----------     |
|   |<a>       \ /          |     |
|   -------------------------     |
|        Event CAPTURING          |
-----------------------------------

Evénements

Bubbling

               / \
---------------| |-----------------
| <p>          | |                |
|   -----------| |-----------     |
|   |<a>       | |          |     |
|   -------------------------     |
|        Event BUBBLING           |
-----------------------------------

Evénements

Arrêter l'événement W3C

function doSomething(e) { [...] e.stopPropagation(); }

Evénements

4. Microsoft

element.attachEvent('onclick',doSomething); element.attachEvent('onclick',doSomethingElse); element.detachEvent('onclick',doSomethingElse);
Seulement du "bubbling"
Support du "this" limité
Un seul événement "global" :
window.event

Pour arrêter l'événement :

window.event.cancelBubble = true;

Evénements

Arrêter l'événement W3C et Microsoft

function doSomething(e) { if (!e) var e = window.event; // Récupération de l'événement pour IE e.cancelBubble = true; // Arrêt de l'évement IE if (e.stopPropagation) e.stopPropagation(); // Arrêt de l'évements W3C }

Pour en savoir plus sur les événements :

Ajax ou Asynchronous JS and XML

function callbackFunction(responseText) { alert(responseText); }; var request = new XMLHttpRequest(); request.open("GET", "http://www.google.com", true); request.onreadystatechange = function() { var done = 4, ok = 200; if (request.readyState == done && request.status == ok) { if (request.responseText) { callbackFunction(request.responseText); } } }; request.send(null);

Ici, on peut parler d'Ajah

Ajax ou Asynchronous JS and XML

Pour supprimer temporairement la "Same Origin Policy" et ainsi faire marcher le code précédent :

try { if (netscape.security.PrivilegeManager.enablePrivilege) netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead"); } catch (e) { alert("Sorry, browser security settings won't let this program run."); }

Plus d'informations sur les privilèges étendus sur mozilla.org/projects/security/...

Ajax ou Asynchronous JS and XML

XMLHttpRequest n'est pas natif sous Internet Explorer < 7

if(typeof XMLHttpRequest == "undefined" ) XMLHttpRequest = function() { try { return new ActiveXObject("Msxml2.XMLHTTP.6.0") } catch(e) {} try { return new ActiveXObject("Msxml2.XMLHTTP.3.0") } catch(e) {} try { return new ActiveXObject("Msxml2.XMLHTTP") } catch(e) {} try { return new ActiveXObject("Microsoft.XMLHTTP") } catch(e) {} throw new Error( "This browser does not support XMLHttpRequest." ) };

Pour leur défense, Ajax est implémenté depuis 1999 dans Internet Explorer 5 via un contrôle ActiveX.

JSON ou JavaScript Object Notation

Les objets sont des tableaux associatifs, vous vous souvenez ?
Donc, le code ci-dessous initialise un objet :

var obj = { name: "Carrot", "for": "Bugs Bunny", details: { color: "orange", size: 12 } };

JSON ou JavaScript Object Notation

JSON est l'idée d'utiliser ce format pour serialiser un objet et de l'évaluer pour l'instancier :

var obj = eval( { name: "Carrot", "for": "Bugs Bunny", details: { color: "orange", size: 12 } }); alert("name:"+ obj.name +" for:"+ obj.for);

JSON est un format très léger donc très intéressant pour stocker et transmettre des objets JavaScript (Ajax > Ajah > Ajaj)

E4X ou ECMAScript for XML

Support natif du XML

var sales = <sales vendor="John"> <item type="peas" price="4" quantity="6"/> <item type="carrot" price="3" quantity="10"/> <item type="chips" price="5" quantity="3"/> </sales>; alert( sales.item.(@type == "carrot").@quantity ); alert( sales.@vendor ); for each( var price in sales..@price ) { alert( price ); }

JavaScript dans le navigateur

  1. Récupération HTML puis parsing (JavaScript "inline" exécuté à la volée)
    récupération CSS puis parsing en parallèle
  2. Reflow(s) (exemples / What is a reflow ? / Make your own reflow video)
  3. Quand le document est chargé, lancement de l'événement "document.onload"

Illustré à travers le schema du moteur de rendu de Gecko.

Tout JavaScript qui touche aux styles CSS, positions, visibilités doit être chargé sur l'événement "onload" !
Une bonne pratique est de câbler toutes les actions JavaScript sur l'onload.

JavaScript dans le navigateur

Les variables, objets, fonctions JavaScript "vivent" tout le temps que la page est affichée.

Lorsqu'on quitte la page, tout le contexte JavaScript est perdu (variables, fonctions, objets) !
C'est pourquoi on charge sur chaque page les mêmes scripts...

Un appel Ajax ne pose aucun problème (car on ne quitte pas la page).

Librairies

Librairies pour masquer les différences entre navigateurs (DOM, événements, Ajax,...) donc pour simplifier le code mais aussi pour animer, pour étendre...

Sans parler des composants : SweetDEV RIA, Yahoo! UI Library, Backbase,...

Liste des frameworks sur Wikipedia [EN] et sur ajaxpatterns.org [EN]

Meilleures pratiques

Insérer du JavaScript de la bonne façon :

<script type="text/javascript"> [...] </script> <script src="..." type="text/javascript"></script>

Evitez le JavaScript "inline"

Meilleures pratiques

Utilisez le mot-clé "var" pour restreindre la portée de vos variables au bloc courant

Et préférez les espaces de noms :

var MyCompany = {}; MyCompany.utils = {}; MyCompany.utils.doMagic = function() { // Magical code };

Evitez l'instruction eval

Meilleures pratiques

Tester les fonctionnalités plutôt que de tester le navigateur

function doSomething(e) { [...] if (e.stopPropagation) e.stopPropagation(); }

Quitte à l'implémenter sous le même nom si le browser n'en dispose pas !

Meilleures pratiques

Accedez aux élements par leurs ID ou leur hiérarchie

Mais simplifiez-vous la vie avec une librairie, ici PrototypeJs :

$('paragraphAboutJavaScript').down('ul').next().hide();

Meilleures pratiques

Attachez les événements sur le "onload" :

document.addEventListener('load', function() { var submitEditorForm = document.getElementById("submitEditorForm"); submitEditorForm.addEventListener('submit',checkThatFormIsOk,false); } ,false);

Idéalement, ajoutez les événements dans un fichier JavaScript et n'ayez plus un seul JavaScript "inline" dans vos pages

Confère code source d'AnotherTodoList

Meilleures pratiques

Simplifiez-vous la vie pour les événements avec une librairie, ici PrototypeJs :

$('foo').observe('click', function(event) { var element = Event.element(event); element.addClassName('active'); Event.stop(event); });

Idem pour Ajax :

new Ajax.Request("http://www.google.com/", { method: 'get', onSuccess: function(transport) { alert(transport.responseText); } });

Sécurité

Cross-site scripting ou XSS

Insère un script malveillant, infectant tous les visiteurs :

Cross-site request forgery ou CSRF

Insère un script malveillant mais destiné uniquement à certains utilisateurs du site (admin) pour effectuer une action à leur insu que eux seuls sont habilités à faire :

Outils

Firefox

Internet Explorer

Références

Références

Questions / réponses

Vos questions ?

Mes réponses !

ROTI ?

1 2 3 4 5
J'ai vraiment perdu du temps J'ai perdu du temps Je n'ai pas perdu mon temps, sans plus J'ai gagné plus que le temps que j'y ai passé. Ça valait bien plus que le temps qu'on y a passé