Tutoriel JsPackage : créer des packages

Abraham Tewa

Abraham Tewa est le concepteur de JsPackage, un framework JavaScript de programmation orienté objet basé sur les classes et les packages.

Commentez

- Titre : Tutoriel JsPackage : créer des packages

- Auteur : Abraham Tewa

- Parution : 12 novembre 2013

- Licence : Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright ® 2013 Abraham Tewa. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. Avant-propos

- II. Présentation

- III. Créer un package

- IV. Déclarer un objet comme parent

- V. Accès aux éléments privés

- V-A. this()

- V-B. $.parent

- VI. Masquer un package

- VII. Conclusion

- VIII. Remerciements

I - Avant-propos

- Tutoriel JsPackage : créer des classes

- Tutoriel JsPackage : créer des packages

JsPackage est un framework JavaScript de programmation orientée objet. Il permet la création d'un ensemble d'objets, tels que des classes, des packages, des interfaces ou encore des namespaces, afin de faciliter la conception et la lisibilité d'application complexes. De plus, la gestion des éléments privés permet de créer efficacement un code solide et sûr.

Le framework n'utilise que des fonctionnalités de JavaScript 1.8.5 (Ecmascript 5), ce qui le rend compatible avec la majorité des plateformes, telles qu'Internet Explorer (9+), Google Chrome, Firefox, mais aussi Node.js.

Pour utiliser JsPackage, importer simplement le fichier JsPackage.js de GitHub dans votre fichier HTML ou votre script Node.js. Ce fichier va ajouter dans l'environnement global (window en HTML ou global dans Node.js) les différents objets nécessaires à l'utilisation de JsPackage.

La documentation est accessible en français et en anglais à cette adresse : wiki.jspackage.net.

II - Présentation

En plus des classes, JsPackage permet de créer des packages. Les packages sont des objets pouvant comporter des propriétés de différents types qui peuvent être publiques ou privées :

- des variables / constantes ;

- des fonctions ;

- des classes ;

- d'autres packages.

Les propriétés privées ne sont visibles que depuis les classes et fonctions du package. Ces propriétés seront aussi accessibles aux fonctions et classes des packages associés.

III - Créer un package

Les packages se créent via la fonction Package. La fonction accepte un objet comme paramètre. Chaque clé de l'objet peut correspondre à une variable, constante ou fonction. Voici un exemple simple de création de package :

var APackage = Package({
aFunction: function() {
return this.aVariable;
}
, aVariable: 'a value'
});

Dans cet exemple, on crée un package comportant une fonction et une variable. La fonction et la variable sont toutes deux publiques.

Pour déclarer une propriété privée, on utilisera le descripteur Private.

var OnePackage = Package({
privateVariable : Private('a value')
, getPrivateVariable : function() {
return this.privateVariable;
}
});

console.log(OnePackage.getPrivateVariable()); // 'a value'
});

IV - Déclarer un objet comme parent

Pour associer une classe ou un autre package à notre package, il faut déclarer celui-ci comme étant parent de la classe/package à associer. Les classes/packages ainsi associés pourront accéder aux propriétés privées du package parent, et réciproquement.

L'association se fait en trois temps :

- déclaration de la propriété dans le package ;

- une classe ou un package déclare le package comme étant son parent ;

- le package parent est scellé de façon à ce qu'aucun autre élément ne puisse être ajouté.

Voici un exemple :

var Geometry = Package({
$ : { seal : false }
, Shapes2D : Public
});

var Shapes2D = Package({
$ : { name   : 'Shapes2D'
, parent : Geometry
, seal   : false}
, Circle : Public
});

Class({
$ : { name           : 'Circle'
, parent         : Shapes2D
, initialization : function(radius) {
this.radius = radius;
}}
, radius : Private
, getRadius : Public(function() {
return this.radius;
})
});

Geometry.$.seal();

var circle10 = Geometry.Shapes2D.Circle(10);

console.log(circle10.getRadius()); // 10

Plusieurs choses sont à noter :

- la propriété $.parent permet de connaître le package parent du package ;

- sceller le package père scellera le package fils aussi. En fait, sceller le package parent scellera l'ensemble des packages fils, petits-fils, etc. ;

- sceller un package fils scellera automatiquement son package parent ;

- Tant que le package parent n'est pas scellé, le package fils n'a pas accès à ces attributs privés. En fait, la propriété $.parent retournera undefined.

V - Accès aux éléments privés

V-A - this()

Le mot-clé standard this est probablement le moyen le plus simple et le plus pratique pour accéder aux éléments privés d'autres objets. En temps normal, this est un objet. Au sein des fonctions et méthodes crées par JsPackage, this est une fonction. Croyez-le ou non, cela reste standard (pour les plus sceptiques, jetez un coup d'œil sur la fonction Object.apply) !

var Geometry = Package({
$ : { seal : false }
, Circle : Public
, changeRadius : function(circle1, newRadius) {
this(circle1).radius = newRadius;
}
});

Class({
$ : { name           : 'Circle'
, parent         : Geometry
, initialization : function(radius) {
this.radius = radius;
}}
, radius : Private
, getRadius : Public(function() {
return this.radius;
})
});

Geometry.$.seal();

var circle10 = Geometry.Circle(10);
console.log(circle10.getRadius()); // 10

Geometry.changeRadius(circle10, 100);
console.log(circle10.getRadius()); // 100

En réalité, this peut être utilisé sur n'importe quel objet, y compris des packages ou des classes/instances d'un autre package, ou même des simples objets, des tableaux, etc. Toutes les fonctions de packages ou méthodes de classes/instances peuvent utiliser this de cette manière. this retournera l'objet avec tous les éléments auxquels la fonction/méthode a accès.

var Geometry = Package({
$ : { seal : false }
, Shapes2D : Public
, getPrivate :
function(obj) {
return this(obj);
}
, packageName : Private('Geometry')
});

var Shapes2D = Package({
$ : { name   : 'Shapes2D'
, parent : Geometry
, seal   : false}
, Circle : Public
, packageName : Private('Shapes2D')
});

Class({
$ : { name           : 'Circle'
, parent         : Shapes2D
, initialization : function(radius) {
this.radius = radius;
}}
, radius : Private
, getRadius : Public(function() {
return this.radius;
})
, className : Static.Private('Circle')
});

Geometry.$.seal();

var circle10 = Geometry.Shapes2D.Circle(10);

console.log(Geometry.getPrivate(Geometry).packageName);      // 'Geometry'
console.log(Geometry.getPrivate(Shapes2D).packageName);      // 'Shapes2D'
console.log(Geometry.getPrivate(Shapes2D.Circle).className); // 'Circle'
console.log(Geometry.getPrivate(circle10).radius);           // 10

S'il n'y a aucun droit particulier, alors on retournera simplement l'objet tel quel.

var TestThis = Package({
doThis :
function(value) {
return this(value);
}
});

console.log(TestThis.doThis(1))   // 1
console.log(TestThis.doThis('a')) // 'a'
console.log(TestThis.doThis([]))  // []
console.log(TestThis.doThis({}))  // {}

V-B - $.parent

Au sein d'une classe, d'une instance de classe ou d'un package, la propriété $.parent permet d'accéder à l'ensemble des éléments publics et privés du package. Exemple :

var society = Package({
$ : { seal : false }
, Employee     : Public
, employeeList : []
, getList      : function() {
return this.employeeList;
}
});

Class({
employeName : Private
, getName     : function() {
return this.employeName;
}
, $ : { initialization : function(employeName) {
this.employeName = employeName;
this.$.parent.employeeList.push(this);
}
, name           :'Employee'
, parent         : society
}
});

society.$.seal();

var JohnSmith = new society.Employee('JohnSmith');

console.log(JohnSmith.getName()); // 'JohnSmith';

VI - Masquer un package

Tous les packages fils, petits-fils, etc. d'un même package ont accès aux propriétés privées des uns et des autres. Cela peut être handicapant quand certains packages ou certaines classes doivent être publics : on ne souhaite pas forcément que tous les packages soient publics.
Il est possible pour un fils de masquer l'existence de son parent. Pour cela, on déclarera le parent comme privé. La propriété $.parent du package ou de la classe retournera alors undefined depuis l'extérieur du package.

var society = Package({
$ : { seal : false }
, Employee     : Public
, employeeList : []
, getList      : function() {
return this.employeeList;
}
});

Class({
employeName : Private
, getName     : function() {
return this.name;
}
, $ : { initialization : function(employeName) {
this.employeName = employeName;
this.$.parent.employeList.push(this);
}
, name           :'Employee'
, parent         : Private(society)
}
});

society.$.seal();

console.log(society.Employee.$.parent); // undefined

VII - Conclusion

Les packages permettent de faciliter la conception et l'organisation du code. Ils ont été pensés pour isoler facilement les composants les plus sensibles avec un minimum d'effort.

VIII - Remerciements

Je tiens tout particulièrement à remercier Cyrille Gachot pour sa relecture et ses conseils sur ce tutoriel, Sophia Tewa et Torgar pour leur relecture orthographique.