Documentation Alpha 2 (basée sur la version 2.1.1 du Framework)
--------------------
Qu'est-ce que la POO ?
La POO est la gestion des classes et des objets.
De nos jours, la majorité des langages sont construit sur le modèle de la POO.
Parmis eux, citons bien sûr les célèbres languages .Net et le portable Java ainsi que l'archaïque C.
Par défaut, JavaScript n'est pas prévu pour fonctionner avec des classes.
Il récupére en effet les objets qu'il utilse de langages de programmation compatible POO et se contente de les manipuler.
Cependant, il existe des astuces pour simuler la POO en JavaScript.
Microsoft en a déjà tiré parti grâce à son framework : Microsoft AJAX
Voici les choses qu'il faut savoir pour commencer :
Creer une classe :
1 2 3
|
function MyClass() {}
var MCI /* for MyClassInstance */ = new MyClass(); |
Tous les objets créés dépuis le code javascript (sans recours direct à window ou document) hérite de Object
Ici, MCI n'a rien de plus qu'un simple objet.
Ajouter un champ (field) à la classe :
1 2 3 4 5 6
|
function MyClass() {
this.aField="value";
}
var MCI = new MyClass();
alert(MCI.aField) |
Un objet javascript est extensible. Cela veut dire que l'on peut à sa guise modifier toutes les propriétés d'un objet (champs, fonctions, ...).
Ajouter un champ dans le constructeur n'a donc d'interêt que si le champ a une valeur de départ (ou dépend d'un paramètre du constructeur)
1 2 3 4 5 6 7
|
function MyClass() {
this.aField="value";
}
var MCI = new MyClass();
MCI.aSecondField="an other value";
alert(MCI.aSecondField) |
Ajouter une fonction à une classe :
1 2 3 4 5 6
|
function MyClass() {
this.alert(text) = function() { alert(text); };
}
var MCI=new MyClass();
MCI.alert("Message"); |
Cependant, cela pose un problème de performance : à chaque fois qu'un objet est crée, la fonction alert est recréée...
Alors, pour palier à ce problème, on a imaginé la propriété prototype.
Chaque nouvelle instance possède toutes les fonctions définies sur prototype.
1 2 3
|
function MyClass() {}
MyClass.prototype.alert=function() { alert(text); } |
Seulement, ce n'est pas très clair, ni très concis.
Avec l'utilisation de nombreuses classes et de nombreuses fonctions par classe, cela s'empire davantage.
Avec cela, pensez-vous, vous avez fait le tour de la POO avec Javascript... Et bien non!
L'héritage :
Comment faire hériter une classe :
1 2 3 4 5 6 7 8
|
function MyClass(argument1) { /*...*/ }
MyClass.prototype.x=function() { /*...*/ }
function MySecondClass {
MyClass.call(this, "A value for the first argument")
/*...*/
}
MySeccondClass.prototype=new MyClass() |
Cela n'est évidemment pas le must point de vue performance... vu qu'il faut crée une nouvelle instance de MyClass, avec tous les problèmes que cela peut poser (arguments, ...)
De plus, tous les champs ajouté par le constructeur de MyClass seront ajouté automatiquement à MySecondClass...
Pour palier le problème, et il faut une copie d'objet.
1 2 3 4
|
// Recopier toutes les propriétés et fonction d'un objet (source) vers un autre (destination)
// Cette fonction est définie dans le FrameWork
AddTo(MyClass.prototype, MySecondClass.prototype); |
L'héritage multiple devient alors permis !
1 2 3 4 5 6 7
|
// Soit C1 et C2 des Classes différentes n'ayant aucun lien d'héritage
function C3() {
C1.call(this)
C2.call(this)
}
AddTo(C1, C3); AddTo(C2, C3); |
Vous avez là un apercu de ce que propose JavaScript du point de vue POO.
Qu'apporte le Framework ?
Il permet l'utilsation d'espaces de nom et simplifie la création de classe et offre des fonctions de rélexion.
Les évènements deviennent de véritable entité comme en .Net.
On peut créer des propriétes avec accesseurs get, set, et un event déclangé après set.
Remarque : Il est IMPOSSIBLE de changer la valeur de la propriété sans passer par le set !
...
Nous allons ici créer un classe et l'utiliser, vous verrez, tout est clair, si on sait que System est un espace de nom.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
// with permet de sous entendre qu'on utilise toujours la valeur retournée par System.addClass(...)
with (System.addClass("MyClass")) {
addSub("alert", function(t) { alert(t); }) // Ajouter un fonction à la classe
addProperty("Property") // Ajoute get/setProperty et l'event onPropertyChange à la classe
addEvent("Testing") // Ajoute l'event onTesting à la classe...
}
var MCI = new System.MyClass();
MCI.alert("");
MCI.onPropertyChange.addHandler(function(sender, e) {
// sender:: l'objet qui a déclanché l'event
// e:: EventArgs, objet envoyé à chaque fonction de l'event en vue du partage de donnée, généralement inutile
sender.alert("La propriété a changé !")
})
alert(MCI.getProperty()) // null
MCI.setProperty("Value"); // Alert grâce à l'event
alert(MCI.getProperty()); // "Value"
// On execute ici l'event 'pour le plaisir'
MCI.onPropertyChange.raise(MCI, System.EventArgs.empty) // Alert grâce à l'event |
Et avec une notion d'héritage :
1 2 3 4 5 6 7
|
// Si vous avez défini un constructeur personalisé (voir plus loin) à la classe héritée, vous devez définir le constructeur avec un appel à MyClass.call
with (System.addClass("C2")) {
inherits(System.MyClass)
}
var C2I = new System.C2();
C2I.alert("text"); |
Ajout de sous-espace de noms et définition de constructeur personalisés
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
with(System.addNameSpace("NS")) { // Création de System.NS
with(addClass("NSClass",
function(nom, age) { // Constructeur de la classe NSClass
/* Cet appel est requis par le Designer de classe */
this.getType().New(this);
/* Vous pouvez ajouter ici tout autre appel prévu par votre fonction */
this.nom = nom;
this.age = age;
}
) { // Ajout d'une classe avec un constructeur personalisé dans System.NS
/*
addSub(...)
addProperty(...)
*/
}
} |
Utilisser la réflexion (sera encore sujet à modification dans le futur) :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
// Nous considérons ici les classes MyClass et C2 et NSClass comme déclarées
var MCI = new System.MyClass();
var Type = MCI.getType(); // Obtenir le type d'un objet depuis une instance
alert(Type.objectName) // "MyClass"
alert(Type.getPath()) // "System.MyClass"
alert(Type.parentType) // "namespace", peut aussi valoir "class" (dans le cas de sous-classes)
alert(Type.parent.objectName) // "System"
/* Astuce : créer un objet du même type qu'un autre
var MCI2 = new MCI.getType()();
*/
var C2Type = System.C2; // Récuperer un type d'objet par son nom (path)
alert(C2Type.getPath()) // "System.C2"
alert(C2Type.baseClass[1].getPath()) // "System.MyClass"
var NSType = System.NS // Récuperer un type d'espace de nom par son nom (path)
alert(NSType.parent.getType().objectName) // "NameSpace"
alert(NS.NSClass.getPath()) // "System.NS.NSClass" |
Lier une fonction à un objet de manière définitive :
1 2 3 4 5 6 7 8 9 10 11 12
|
var MCI=new System.MyClass();
var MCIPropertySetter = CreateDelegate(MCI.setProperty, MCI) // Renvoie une fonction qui est lié avec l'objet passé en seccond argument
// Changer la valeur de la propriété Property de MCI
MCIPropertySetter("Value"); // Ok
// Le refaire, mais en attachant la fonction à une autre objet
var MCI2=new System.MCI();
MCI2.setMCIProperty=MCIPropertySetter;
MCI2.setMCIProperty("A seccond value");
alert(MCI.getProperty()) // Ca marche !!! |
Le Framework permet encore plein de chose, que vous pourrez découvrir par vous même...
Partager