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é…
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.
Comme vous le savez peut-être, dans JavaScript tout est objet ou référence à un objet (tableau associatif) :
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 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.
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; }
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 ?
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"
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 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é"
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 :
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 ) { ... }
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.
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é…