Bienvenue à Blogs CodeS-SourceS Identification | Inscription | Aide

Actualités

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

    View Cyril Durand's profile on LinkedIn

    hit counters

Créer un type JavaScript à partir de son nom : Type.createInstance

Je me suis retrouvé tout à l'heure à devoir créer un type JavaScript en ayant seulement son nom et les arguments du constructor. Voici la signature de la fonction que je devais alors coder.

Type.createInstance = function(typeName, args){ /// <summary> /// Create an objet of the specified type with the specified arguments. /// </summary> /// <param name="typeName" type="String">Name of the type to create.</param> /// <param name="args" type="Array">Arguments of the constructor.</param> /// <return type="Object">Returns the specified instance of the object.</return> }

Comment faire ? Réfléchissons à notre besoin : créer une instance d'un objet en ne connaissant que son nom et un tableau de paramètre. J'ai pensé à la méthode eval qui exécute du code sous sa forme littéral, il m'aurait alors suffit de créer un string contenant le code à exécuter. Cette solution me satisfaisait pas parce que les arguments ne sont pas tous de type simple, il m'aurait fallut serialiser les arguments. Et puis je n'aime pas eval qui souvent ralenti le code.

J'ai donc pensé à la méthode apply de l'objet Function, celle-ci permet d'appeler une fonction d'un autre objet avec un tableau de paramètre, j'avais déjà parlé de cette méthode avec sa cousine call ici : JavaScript : un langage incompris - Appel de fonctions. Après quelques essais voici le résultat.

Type.createInstance = function(typeName, args){ /// <summary> /// Create an objet of the specified type with the specified arguments. /// </summary> /// <param name="typeName" type="String">Name of the type to create.</param> /// <param name="args" type="Array">Arguments of the constructor.</param> /// <return type="Object">Returns the specified instance of the object.</return> var propType = Type.parse(typeName); var newType = function(){}; newType.prototype = propType.prototype; var obj = new newType(); propType.prototype.constructor.apply(obj, args); return obj; }

Tout d'abord je récupère le type de l'objet grâce à la méthode Type.parse du framework client Microsoft Ajax. Ensuite je déclare un nouveau type vide, je définis le prototype de ce type de façon à ce qu'il corresponde au prototype du type à créer. Puis je créer une instance du type vide. Cet instance possède le prototype recherché, techniquement c'est une instance de l'objet typeName mais sans que son constructeur ait été appelé, il me reste alors a appelé le constructor du type recherché sur mon objet. Cela se fait en utilisant la méthode apply sur la fonction constructor du prototype du type recherché.

Après analyse de mon code je me suis posé une question : que se passe t'il en mémoire ? est-ce que le prototype est partagé par les deux types ? ou alors est-il copié ? J'ai effectué quelques tests et le prototype est bien partagé entre mes deux types ! En utilisant cette méthode seul le constructeur type vide est conservé en mémoire c'est à dire une fonction vide donc pas grand chose.

J'avais trouvé une autre solution que je donne à titre informatif. Je ne vous conseil pas de l'utiliser puisqu'il peut y avoir des problèmes de "thread". En effet cette solution modifie le constructeur du type le temps de la création de l'instance de mon objet. Si ailleurs dans le code, un autre "thread" créer une instance de ce type celui ci ne sera pas appelé et cela peut vite causer des problèmes ...

var propType = Type.parse(typeName); var constructor = propType.prototype.constructor; propType.prototype.constructor = function(){}; var obj = new propType(); propType.prototype.constructor = constructor; return obj;

Je ne suis pas sur d'avoir été bien clair sur l'explication du code, si vous voulez en savoir plus, les commentaires sont là pour ça :-)

Posted: samedi 13 janvier 2007 22:09 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

FREMYCOMPANY a dit :

Moi ca me semble assez clair.

Mais ca risque de caller si tu teste ton objet via instanceof, non ?

# janvier 14, 2007 13:15

cyril a dit :

J'ai testé mais j'en ai pas parlé pour ne pas complexifier mon poste.

debug.trace(obj instanceof Itelios.Geo.Point); me retourne true :-) et Object.getTypeName(obj) me renvoie bien Itelios.Geo.Point. Donc tout est bon :-)

# janvier 14, 2007 13:35

Zorglub a dit :

function monType(a,b,c){this.b=b}

var inst=new window['monType'](1,2,3)

alert(inst.b) // 2

ca marche aussi ;)

# avril 15, 2007 06:28

cyril a dit :

Zorglub : As tu bien lu mon post ?

La question est comment créer une instance d'un type en ayant les arguments dans un tableau !

var args = [1,2,3]

var inst = new window[typeName](args)

ne fonctionne pas !

et puis déclaré des objets directement dans l'objet window c'est pas ce qu'il y a de plus propre ...

# avril 15, 2007 12:51

Zorglub a dit :

&gt; Zorglub : As tu bien lu mon post ?

&gt; La question est comment créer une instance d'un type

&gt; en ayant les arguments dans un tableau !

^^' ... j'ai principalement lu le titre... en fait :]

"Créer un type JavaScript *à partir de son nom*"

(nan mais c'est ça aussi de de poster à 6h du mat... ^^)

bon j'ai regardé plus sérieusement et c'est vrai que c'est bien trouvé Cyril :)

J'ai essayé de le refaire autrement, sans grand succès.

je propose une légère variante en closure qui offre l'avantage de renvoyer un constructor (ca peut etre pratique pour le stocker et l'appeler directement pour les autres instances).

function createInstance(typeName, args){

 return new (createConstructor(typeName,args))

}

function createConstructor(typeName, args){

 var propType = window[typeName] // ou Type.parse(typeName) si MicrosoftAjax actif

 function f(){propType.apply(this,args)}

 f.prototype=propType.prototype

 return f

}

// Test:

function monType(a,b,c){// Pas vraiment un type MSAjax, mais c'est pour la demo

 this.a=a

 this.c=c

 this.toString=function(){

   return this.a+' '+this.b+' '+this.c

 }

}

monType.prototype.b=2

var o=createInstance('monType',[1,0,3])

var a=createInstance('monType',[1,0,3])

alert(o instanceof monType) // true

o.constructor.prototype.b=-2

o.b=2

alert(o) // 1 2 3

alert(a instanceof monType)

alert(a) // 1 -2 3

# avril 16, 2007 08:45

Zorglub a dit :

petite correction dans f()

la bonne fonction est :

function f(){propType.apply(this,args||arguments)}

cela permet d'utiliser

var o=createInstance('monType',[1,0,3])

ou

var C=createConstructor('monType'),

   o=new C(1,0,3)

(ce dernier cas n'est pas tellement utile pour le problème posé ici)

# avril 16, 2007 09:13
Les commentaires anonymes sont désactivés

Les 10 derniers blogs postés

- TCB : Travailler en équipe sans réseau par The Mit's Blog le il y a 12 minutes

- Accès anonyme et les pages Forms / viewlsts.aspx... par Nicolas Humann le il y a 4 heures et 5 minutes

- l'Atelier 4 du coach C# est disponible par Bernard Fedotoff le il y a 5 heures et 41 minutes

- [WPF] Formatter l’affichage lors d’un binding, via StringFormat par Thomas Lebrun le il y a 10 heures et 43 minutes

- WSC08 : Le bilan, Les Photos, Les Webcasts à voir ou à revoir par Blog de Daniel TIZON [daniel] le il y a 19 heures et 50 minutes

- SharePoint et ses DB : Avez vous pensé à les "Tweaker" ? par The Mit's Blog le il y a 20 heures et 19 minutes

- NTttcp : Mesurer la vitesse d'un réseau par Blog d'Olivier Huet le il y a 20 heures et 44 minutes

- Un nouveau quizz par Matthieu MEZIL le il y a 23 heures et 28 minutes

- Webcast ADO.NET Data Services par Matthieu MEZIL le il y a 23 heures et 31 minutes

- edmx : mise à jour du modèle depuis la base par Matthieu MEZIL le 10-06-2008, 17:47