(re)découvrir javascript

Introduction

A la lecture de ce tutoriel j’espère vous faire découvrir des aspects méconnus de ce langage passionnant souvent délaissé par les développeurs.

Javascript est un langage de script orienté objet, mis à part le nom, il n’a aucun lien avec java, je dirai qu’il est plus inspiré de Self. Un des vieux problèmes de JavaScript est qu’il a souffert de la guéguerre des navigateurs ( IE vs Netscape ). En effet il a été crée par Netscape mais implémenté par Microsoft, qui comme à son habitude l’a remoulé à sa sauce…

Depuis l’ère du Web 2.0 il est redevenu à la mode avec un certain XMLHttpRequest… Malgré cela, il est toujours aussi peu considéré par les programmeurs coté serveur.Aussi certains de ces aspects sont ignorés, essayons de le dépoussiéré…

Rappel sur ECMAScript

C’est une spécification de l'organisme de standardisation "Ecma International" qui date de 1997. En fait ECMAScript (ECMA-262) correspond à JavaScript Core (hors browser et DOM), seulement à ce jour il n’y aucune implémentation connue.

Les technologies JavaScript et JScript tendent désormais à l'implémentation du standard tout en proposant de nouvelles fonctionnalités pas (encore) incluses dans ECMAScript.

Aspects techniques méconnus

Comme vous le savez peut-être, dans JavaScript tout est objet ou référence à un objet (tableau associatif) :

Définition d’un objet

3 formes possibles :

 // Création de l'objet

var MonObjet = new Object;

// Définition classique

MonObjet.attribut = "Attribut";

MonObjet.fonction = function() {

return "Fonction";

}

// Définition en mode tableau associatif

MonObjet['attribut' *  = "Attribut";

MonObjet['fonction' *  = function() {

return "Fonction";

}

// Définition en mode HashMap ( key/value )

var MonObjet = { attribut: 'Attribut' , fonction: function() { return 'Fonction'; } };


Accès aux « données » de l’objet

// Accès normal

MonObjet.attribut; //retourne "Attribut"

MonObjet.fonction() ; //retourne "Fonction"

// Accès tableau associatif

MonObjet['attribut' * ; //retourne "Attribut" (équivalent à MonObjet.attribut)

MonObjet['fonction' * ; : //retourne : function () { return "Fonction"; }

MonObjet['fonction' * (); //retourne "Fonction" (équivalent à MonObjet.fonction())


===Constructeur===Les constructeurs permettent d’instancie des objets plus complexes, les constructeurs instancient des propriétés communes à une catégorie d’objets ( notion de classe d’objet ). Cette fonction est exécutée à la création de l’objet ( mot clé new ), elle est accessible par la propriété « constructor » de l’instance.

function MonObjetComplexe(param) {

this.description = param;

this.maMethode = function() {

return "Je suis un objet complexe.";

}

}

var o = new MonObjetComplexe("Trop de bla bla");

o.description; //contient "Trop de bla bla"

o.maMethode(); //retourne "Je suis un objet complexe."

A noter que le mot clé this dans le corps du constructeur fait référence à l'objet en cours de création.

Prototypage

Le « prototype » est un objet associé à toute fonction comme référence par les objets créés. Il est accessible via la propriété “prototype” du constructeur. Il existe un mécanisme de remontée des prototypes de récupération de la valeur d'une propriété (existante ou pas) :

- si elle existe au niveau de l'objet, sa valeur est retournée,

- sinon, recherche au niveau du prototype de l'objet,

- sinon, recherche au niveau du prototype du prototype,

- ainsi de suite…

- sinon, retourne “undefined”

L’attribut prototype d’un constructeur permet de modifier dynamiquement des objets créés avec le même constructeur :

function MonObjetComplexe(param) {

this.description = param;

}

var o = new MonObjetComplexe("Trop de bla bla");

// Modification dynamique de toutes les instances de MonObjetComplexe

MonObjetComplexe.prototype.maMethode = function() {

return  "Je suis un objet complexe.";

}

// On obtient comme précédemment

o.maMethode(); //retourne "Je suis un objet complexe."

Cette fonctionnalité prévaut également pour les constructeurs prédéfinis de JavaScript :

String.prototype.startsWith = function(pattern) {

    return this.indexOf(pattern) === 0;

}

Array.prototype.contains = function( object ){

       if ((typeof object == "function") && this.indexOf(object) != -1) return true;

       
       for (var i <bold>0, length</bold> this.length; i < length; i++)

               if( this[i *  == object )

                       return true;

       return false;

}

Héritage ( Si si ça marche … )

En fait, l’héritage se fait par assignation de l’objet père au prototype du fils, c’est dynamique et ça marche par remontée de la hiérarchie des prototypes :

// Définit le constructeur parent

function Felin() {

       this.griffer = function() {

               return "Griffure de " + this.profondeur + " centimetres";

       }

}

// Definit un autre constructeur

function Lion(param) {

       this.profondeur = param;

}

// Affecte a ce constructeur le constructeur parent

Lion.prototype = new Felin();

Lion.prototype.constructor = Felin;

// Ajoute une méthode

Lion.prototype.attaquer = function() {

       return "Grrr grrrr grrr";

}

var monFelin = new Lion("3");

// Ajoute une autre méthode

Felin.prototype.deguerpir = function() {

       return "Bye bye";

}

//monFelin.griffer() retourne : "Griffure de "

//monFelin.attaquer() retourne : Grrr grrrr grrr

//monFelin.deguerpir() retourne :Bye bye

Impressionnant non ?

Encapsulation

Propriétés publiques

Les composants (attributs ou méthodes) d'un objet sont, par défaut, accessibles a tous :

function ObjetA() {

       this.attribut = "Attribut public";

}

ObjetA.prototype.fonction = function() {

       return "Fonction publique";

}

var MonObjetA = new ObjetA();

MonObjetA.attribut; //contient "Attribut public"

MonObjetA.fonction(); //retourne "Fonction publique"

Propriétés privées

Elles sont créés dans le constructeur et accessibles seulement via les méthodes privées de l'objet lui-même :

function ObjetB() {

       var attribut = "Attribut privé";

       function fonction() {

               return "Fonction privée";

       }

}

var MonObjetB = new ObjetB();

MonObjetB.attribut; //contient "undefined"

MonObjetB.fonction(); //retourne l'erreur "MonObjetB.fonction() is not a function"

Vous allez me dire, ok, mais comment on accède à la propriété privée attribut, suivez le guide… Par les

Méthodes privilégiées

Méthodes pouvant accéder aux composants privés de l'objet tout en étant accessibles depuis l'extérieur :

function ObjetC() {

       var attribut = "Attribut privé";

       this.fonction = function() {

               return(attribut);

       };

}

var MonObjetC = new ObjetC();

MonObjetC.fonction(); //retourne "Attribut privé"

Typage

JavaScript est dynamiquement typé mais cela ne veut pas dire qu'il n'est pas typé.

Il existe des types primaires en JavaScript (number, string, object, boolean, function, undefined). Mais tous les types sont récupérables via l'opérateur typeof.

Le typage est une autre manière de voir: constructor.name :

  • Object : objet générique non typé,
  • Boolean: booléen (vaut true ou false),
  • Number: nombre entier ou décimal,
  • String: chaîne de caractères,
  • Array: tableau,
  • Function: fonction contenant une portion de code,
  • [NomConstructeur * : type défini par l'utilisateur via une fonction constructeur.

Exceptions

Comme dans les langages évolués :

//try... catch... finally

try {

       // Code à tester

       throw "Erreur 1"; // Une exception est levée

} catch(erreur) {

       // Code à exécuter en cas d'erreur

       // erreur = “Erreur 1”

} finally {

       // Code à exécuter dans les deux cas

}

Une particularité Mozilla permet d’empiler les instructions catch :

 try { ... }

catch ( e if e == "InvalidIdException" ) { ... }

catch ( e if e == "InvalidEmailException" ) { ... }

catch ( e if e == "InvalidNameException" ) { ... }

catch ( e ) { ... }

Closures

Ce vilain mot désigne en fait le contexte d'exécution de fonctions imbriquées. La fonction contenue accède aux propriétés de la fonction contenante même après l'exécution de la fonction contenante. C’est magique !

function CreerAction(action) {

       return function() {

               return "Je suis en train de " + action;

       }

}

function Chat() {

       this.dormir = CreerActionVoiture("dormir");

       this.manger = CreerActionVoiture("manger");

       this.griffer = CreerActionVoiture("griffer");

}

var monChat = new Chat();

//monChat.dormir() retourne : Je suis en train de dormir

//monChat.manger() retourne : Je suis en train de manger

//monChat.griffer() retourne : Je suis en train de griffer

Une fois que vous connaissez ce mécanisme, vous comprendrez enfin certaines erreurs incompréhensibles pour un novice, en effet il est très facile de créer des closures sans s’en rendre compte.

ECMAScript for XML (E4X)

Il existe un nouveau type d'objet XML à présent implémenté par Mozilla et Adobe, peut être un jour par Microsoft, il s’utilise ainsi :

var motos = new XML();

motos = <motos>

<moto marque="Suziki" modele="modele2Suziki"/>

<moto marque="Harley" modele="modele1"/>

<moto marque="Honda" modele="modele2Honda"/>

</motos>;

alert(motos.moto.(@marque == "Honda").@modele);

//Affiche: modele2Honda

for each(var moto in motos..@marque) {

alert(moto);

}//Affiche :

//Suziki

//Harley

//Honda

C’est assez prometteur pour les échanges via web-service et l’interopérabilité…

Ce document intitulé « (re)découvrir javascript » issu de CodeS SourceS (codes-sources.commentcamarche.net) est mis à disposition sous les termes de la licence Creative Commons. Vous pouvez copier, modifier des copies de cette page, dans les conditions fixées par la licence, tant que cette note apparaît clairement.
Rejoignez-nous