Bienvenue à Blogs CodeS-SourceS Identification | Inscription | Aide

Atteint de JavaScriptite Aiguë [Cyril Durand]

Expert ASP.net Ajax et WCF, Cyril Durand parle dans son blog de point techniques sur ASP.net, ASP.net Ajax, JavaScript, WCF et .net en général. Cyril est également consultant indépendant, n'hésitez pas à le contacter pour de l'assistance sur vos projets

Actualités

  • Blog de Cyril DURAND, passionné de JavaScript, Ajax, ASP.net et tout ce qui touche au developpement Web Client-Side.

    N'hésitez pas à me contacter pour vos projets .net : architecture, accompagnement, formation, ...

    View Cyril Durand's profile on LinkedIn
    hit counters


    Expertise Commerce server et BizTalk

Prototype Vs Closure - optimisation d'une classe en JavaScript

En JavaScript, il y a 2 grandes façons de faire une classe : le mode prototype et le mode closure.

Méthode closure :

var Foo = function(){ this.method = function(){ return 'test'; } }

Méthode prototype :

var Foo = function(){ } Foo.prototype.method = function(){ return 'test'; }

Dans les 2 cas, on peut utiliser l'objet de la même façon.

var foo = new Foo(); foo.method();

Pourquoi est-il conseillé d'utiliser la méthode prototype plutôt que la méthode closure ?

C'est principalement une question de performances. Lors de la création d'un objet "closure", le constructeur est parsé/executé, il y a donc création des différentes méthodes qui appartiennent alors à l'instance de l'objet. Avec une classe "prototype" les méthodes sont déjà instanciées lors de la création du type et appartiennent à l'instance du prototype de l'objet, deux instances d'une même classe partagent le même prototype. Cela a deux incidences :

  • La création de l'objet sera plus longue à cause de la création des méthodes membres.
  • L'instance de l'objet prendra plus de mémoire car les méthodes membres ne sont pas partagées entre les objets.

Pour le prouver j'ai créé 100 000 instances de Foo puis regardé la consommation mémoire ainsi que le temps de création.

  prototype closure
IE7 25 332 ko 568 ms 108 900 ko 976 ms
FF2 39 612 ko 953 ms 56 976 ko 1 236 ms
Opera 9.23 25 008 ko 284 ms 45 882 ko 674 ms
Safari 3.0.3 55 820 ko 240 ms 59 124 ko 333 ms

J'ai relancé le navigateur entre chaque test. Voici le code utilisé :

var foos = []; var d = new Date(); for (var i = 0; i < 100000; i++){ foos.push(new Foo()); } alert((new Date()) - d);

La classe utilisé pour les tests est très simple, mais lorsqu'il s'agit d'objet complexe avec des dizaines de méthodes qui contiennent des dizaines de lignes, alors c'est tout ce contenu qui sera dupliqué en mémoire pour chaque instance.

Si vous utilisez des classes JavaScript et que vous utilisez le mode closure, vous savez maintenant comment optimiser votre application JavaScript ...

Dans les version betas de Microsoft Ajax (Atlas), le mode closure était utilisé. Bertrand Leroy a publié sur son blog un guide de migration du mode closure vers le mode prototype (part 1) et (part 2).

Posted: mardi 16 octobre 2007 13:49 par cyril
Ce post vous a plu ? Ajoutez le dans vos favoris pour ne pas perdre de temps à le retrouver le jour où vous en aurez besoin :

Commentaires

RaptorXP a dit :

Avec le mode prototype, comment avoir des variables et méthodes privées ?

# octobre 16, 2007 14:07

cyril a dit :

Je viens d'éditer mon post, j'avais oublié le lien de l'article de Bertrand Leroy qui explique comment migrer de closure vers prototype.

En JavaScript il n'existe pas vraiment la notion de public / private. Bien sur on peut émuler ce comportement en faisant

var Foo = function(){

  var _private = 'toto';

  this.method = function(){

      return _private;

  }

}

Mais on ne peut pas s'assurer qu'une méthode est bien celle d'origine et qu'il n'y a pas eu de "hook" dessus.

La notion de portée de variable n'a donc aucun sens ...

Par convention dans ASP.net Ajax, un membre privé commence par _ mais c'est juste une convention ca ne garanti en rien quoi que ce soit.

# octobre 16, 2007 14:47

RaptorXP a dit :

C'était un point que je voulais souliger dans mon post (http://blogs.developpeur.org/raptorxp/archive/2007/10/11/pourquoi-ne-faut-il-plus-utiliser-l-h-ritage-de-classe.aspx) mais comme je n'étais pas sur, je ne l'ai pas évoqué.

Si on veut pouvoir utiliser l'héritage, on est obligé d'utiliser les prototypes, et dans ce cas il est impossible de simuler des variables privées. On doit donc choisir entre l'héritage ou l'encapsulation: c'était un de mes arguments lorsque je disais que JS est mal équipé au niveau programmation objet.

# octobre 16, 2007 15:21

cyril a dit :

Raté ;-)

On peut utiliser l'héritage et les variables privés, ce sera juste un héritage par recopie plutot qu'un héritage par prototype.

/* héritage par "recopie" (mal)*/

var Foo = function(){

   var _private = 'private';

   this.method = function(){

       return _private;

   }

}

var Bar = function(){

   Foo.apply(this, []);

   this.method2 = function(){

       return this.method();

   }

}

var b = new Bar();

alert(b.method2());

cela va bien nous renvoyer "private". Là encore on peut utiliser de l'héritage multiple et on peut aussi appeller une méthode de l'objet de base en créant une nouvelle instance (que je met en cache en membre static de la classe parent)

var Toto = function(){

   Bar.apply(this, []);

   this.method2 = function(){

       var tmp = (Bar._instance=Bar._instance||new Bar()).method2.apply(this, []);

       return tmp + ' yes';

   }

}

Mais je ne conseil pas cette solution pour des raisons de perfs ! Vouloir émuler des membres privées n'a aucun sens en JavaScript puisqu'on peut "hooker" tout ce qu'on veut.

# octobre 16, 2007 16:00

FREMYCOMPANY a dit :

En effet, si on a un membre privé, on fait simplement un obj.privateFieldGetter = function() { return this.anyPublicField; } puis un obj.anyPublicField = theNewValue...

# octobre 16, 2007 18:54

RaptorXP a dit :

Voila ! Et à mon avis (ce n'est peut être pas celui de tout le monde), l'encapsulation (qui passe forcément par des variables privées "sures") est un concept essentiel en POO.

# octobre 16, 2007 19:16

cyril a dit :

Euh Fremy ta solution ne permet pas d'accéder à une variable privé. A ma connaissance on ne peut pas le faire puisqu'il faudrait éxécuter une fonction dans le scope du constructeur et je ne vois pas comment executer une fonction dans un scope précis, je doute que ce soit possible.

Je pense que les variables privées sont "sures".

RaptorXP : Tout dépend de la définition de la POO c'est un concept très vaste. Pour moi JavaScript est beaucoup plus souple niveau objet que C#/Java puisqu'on est pas contraint par les enveloppes qui sont les types, c'est une question de point de vue et d'habitude ;-)

# octobre 16, 2007 20:41

FREMYCOMPANY a dit :

Oui, OK, ma méthode ne permet pas de changer la valeur de 'la variable privée'.

Mais on parlait juste avant "d'encapsulation", donc de la création d'un getProperty et d'un setProperty.

Une fois qu'on crée ces deux méthodes, il est possible de 'faire croire' que la propriété a changé rien qu'en modifiant le couple get/set. Même si la vraie valeur privée n'a pas changée...

Ce n'est donc pas la variable privée qui change, mais son exposition au monde extérieur.

______________________________________

Mais de toute façon, une variable privée n'est jamais sûre à 100%, quoiqu'il arrive, vu que de toute façon, on peut faire aussi ceci (pseudo-code) :

for (funcName in obj &amp;&amp; typeof(obj[funcName])=="function") ==&gt; obj[funcName]=eval((""+obj[funcName]).replace(/(\b)thePrivateVarName(\b)/g, "this.theNewVarName")

On sort alors de la closure toutes les fonctions et on rend inefficace la variable privée. Bien sûr c'est lent et couteux, mais c'est toujours possible.

Par contre, impossible de lire la variable privée si elle n'est pas exposée, je suis bien d'accord sur ce point.

# octobre 17, 2007 14:21
Les commentaires anonymes sont désactivés

Les 10 derniers blogs postés

- Office 365: Nettoyage des versions de List Item avant migration depuis SharePoint On Premise vers SharePoint Online par Blog Technique de Romelard Fabrice le 08-08-2017, 15:36

- Office 365: Comment supprimer des éléments de liste SharePoint Online via PowerShell par Blog Technique de Romelard Fabrice le 07-26-2017, 17:09

- Nouveau blog http://bugshunter.net par Blog de Jérémy Jeanson le 07-01-2017, 16:56

- Office 365: Script PowerShell pour assigner des droits Full Control à un groupe défini par Blog Technique de Romelard Fabrice le 04-30-2017, 09:22

- SharePoint 20XX: Script PowerShell pour exporter en CSV toutes les listes d’une ferme pour auditer le contenu avant migration par Blog Technique de Romelard Fabrice le 03-28-2017, 17:53

- Les pièges de l’installation de Visual Studio 2017 par Blog de Jérémy Jeanson le 03-24-2017, 13:05

- UWP or not UWP sur Visual Studio 2015 ? par Blog de Jérémy Jeanson le 03-08-2017, 19:12

- Désinstallation de .net Core RC1 Update 1 ou SDK de Core 1 Preview 2 par Blog de Jérémy Jeanson le 03-07-2017, 19:29

- Office 365: Ajouter un utilisateur ou groupe dans la liste des Site collection Administrator d’un site SharePoint Online via PowerShell et CSOM par Blog Technique de Romelard Fabrice le 02-24-2017, 18:52

- Office 365: Comment créer une document library qui utilise les ContentTypeHub avec PowerShell et CSOM par Blog Technique de Romelard Fabrice le 02-22-2017, 17:06