JeuWeb - Crée ton jeu par navigateur
[JS] Invoquer dynamiquement une methode sur une class - Version imprimable

+- JeuWeb - Crée ton jeu par navigateur (https://jeuweb.org)
+-- Forum : Discussions, Aide, Ressources... (https://jeuweb.org/forumdisplay.php?fid=38)
+--- Forum : Programmation, infrastructure (https://jeuweb.org/forumdisplay.php?fid=51)
+--- Sujet : [JS] Invoquer dynamiquement une methode sur une class (/showthread.php?tid=7112)

Pages : 1 2 3 4


RE: [JS]Invoquer dynamiquement une methode sur une class - Argorate - 13-08-2013

J'ai pris un exemple tout bête oui, c'est juste un exemple pour se concentrer sur l’essentiel, je ne cherche pas a faire un truc aussi bête en vrai Smile

Bon pour être plus clair peut être (même si je trouve que ça complique):

je recoie les données d'un push qui contient les infos des fighters de mon combat. Le but est d'initialiser celui-ci. Pour ce faire j'ai besoin d'instancier mes Fighters coté JS, sauf qu'à la différence de Rails qui fait tout de manière transparente via active reacord + l'option polymorphic (qui utilise un champs type dans la table qui contient le nom de la class pour savoir laquelle instancié par la suite), moi en JS, je dois le faire moi même.

Ce que je veux donc éviter c'est d'avoir à faire:

if(data.className == 'Character') new Charater(data);
else if(data.className == 'Mob') new Mob(data);
...

le but étant de ne pas avoir des choses en dur pour une meilleur maintenabilité/évolutivité.

Donc j'aimerais pouvoir faire: new data.className(); mais donc la solution proposé tout à l'heure ne marche pas.


RE: [JS]Invoquer dynamiquement une methode sur une class - srm - 13-08-2013

Et pourtant...

http://fr.wikipedia.org/wiki/Fabrique_(patron_de_conception)


RE: [JS]Invoquer dynamiquement une methode sur une class - Argorate - 13-08-2013

Oui c'est du java l'exemple, le truc bien naz où tu fais les if dont je parle, j'aimerais croire que le JS peut s'en passer... J'ai pas envi d'avoir un truc en dur, c'est la loose absolue Smile


RE: [JS]Invoquer dynamiquement une methode sur une class - Maks - 13-08-2013

Tu peux simplement changer le nom de ton event lorsque tu reçois tes données, player:joined => new Player..., mob:joined => new Mob...

Sinon une fabrique comme propose oxman, c'est propre

Citation :Oui c'est du java l'exemple, le truc bien naz où tu fais les if dont je parle, j'aimerais croire que le JS peut s'en passer... J'ai pas envi d'avoir un truc en dur, c'est la loose absolue

Les design patterns Java se transposent plutôt bien en Javascript, y'a pas mal d'article là dessus


RE: [JS]Invoquer dynamiquement une methode sur une class - Xenos - 13-08-2013

Citation :c'est du code client, tu peux exécuter n'importe quelle fonction à la volée via la console
Ce n'est pas une raison, car si le code est passé, par exemple, par variable get, je peux faire un lien vers le site d'Argorate, avec dedans mon propre code Javascript. Et bonjour XSS, ça faisait longtemps... T'as passé de bonnes vacances?

La solution de Maks est appropriée.
Sinon:

function Toto()
{
this.test=function(i){
var t;
if(i==1) t='func1';
else t='func2';

var temp = new Toto();
temp[t]();
};

this.func1=function()
{console.log('1');}

this.func2=function()
{console.log('2');}
}

new Toto().test(1);

Rien ne t'empêche de faire un compromis entre le pattern souligné par Oxman et ton envie de ne rien faire en dur:
tu peux faire de Toto une usine à qui tu passes une chaine de caractères ou un index (comme test(1)) et qui te renvoie le nouvel objet, sans avoir un espèce de "switch" ou "if" en dur dans le code de Toto.
Bon, en revanche, avec un "new Toto()" dans "Toto", fais gaffe à ne pas faire de la boucle infinie... En d'autres mots, le "new Toto()" doit être dans une méthode de Toto, et surtout pas directement dans Toto() même (sinon, tu crash le navigateur, comme je l'ai moi même fait \o/)

Exemple:

function UsineAGaz()
{
this.produire = function(p_nom)
{
console.log('On me demande le gaz:',p_nom);
var usineTemporaire = new UsineAGaz();
var ceGazCi = usineTemporaire['Gaz'+p_nom];
if (typeof ceGazCi == 'function')
return new ceGazCi();
console.warn('Le gaz "',p_nom,'" n\'existe pas.');
return new this.GazDefaut();
}

this.GazXenon = function ()
{
this.saluer = function()
{
console.log('Je suis rare, donc précieux');
};
}
this.GazSchiste = function ()
{
this.saluer = function()
{
console.log('Je pue et je pollue !');
};
}
this.GazEau = function ()
{
this.saluer = function()
{
console.log('Y\'a de l\'eau dans le gaz.');
};
}
this.GazDefaut = this.GazEau;
}
var Usine = new UsineAGaz();
Usine.produire('Eau').saluer();
Usine.produire('pard').saluer();
Usine.produire('Schiste').saluer();
Usine.produire('Xenon').saluer();

Firebug (et f** le charset=utf-8) a écrit :On me demande le gaz: Eau
Y'a de l'eau dans le gaz.
On me demande le gaz: pard
Le gaz " pard " n'existe pas.
Y'a de l'eau dans le gaz.
On me demande le gaz: Schiste
Je pue et je pollue !
On me demande le gaz: Xenon
Je suis rare, donc précieux

Similaire à Factory, sans expliciter chaque gaz dans le code de "fabrication". MAIS impossible de changer le nom des gaz sans devoir refaire un bout de code (ex: changer GazEau en GazRien obligera à ajouter un ligne de code dans "produire()" pour traiter les anciens appels à GazEau).

Egalement, j'aurai personnellement mis les gaz ailleurs que dans l'Usine elle-même, c'est pas franchement le must (dans un "ListeGaz()" par exemple).


RE: [JS]Invoquer dynamiquement une methode sur une class - Maks - 13-08-2013

Code :
Ce n'est pas une raison, car si le code est passé, par exemple, par variable get, je peux faire un lien vers le site d'Argorate, avec dedans mon propre code Javascript.

Prendre le cas ultime d'une erreur de programmeur pour en faire un argument c'est hors sujet.


function UsineAGaz()
{
this.produire = function(p_nom)
{
console.log('On me demande le gaz:',p_nom);
var usineTemporaire = new UsineAGaz();
var ceGazCi = usineTemporaire['Gaz'+p_nom];
if (typeof ceGazCi == 'function')
return new ceGazCi();
console.warn('Le gaz "',p_nom,'" n\'existe pas.');
return new this.GazDefaut();
}

this.GazXenon = function ()
{
this.saluer = function()
{
console.log('Je suis rare, donc précieux');
};
}
this.GazSchiste = function ()
{
this.saluer = function()
{
console.log('Je pue et je pollue !');
};
}
this.GazEau = function ()
{
this.saluer = function()
{
console.log('Y\'a de l\'eau dans le gaz.');
};
}
this.GazDefaut = this.GazEau;
}
var Usine = new UsineAGaz();
Usine.produire('Eau').saluer();
Usine.produire('pard').saluer();
Usine.produire('Schiste').saluer();
Usine.produire('Xenon').saluer();

Pourquoi tu mélanges le UpperCamelCase, le snake_case et le camelCase dans tes codes ? En Javascript le camelCase c'est la norme.

On utilise les prototypes plutôt que les closures.

Code :
return new this.GazDefaut();

assez horrible comme notation et mal pensé, tu instancies des objets à partir de méthodes de ta classe

Ta méthode produire est intestable, tu ré-instancie l'objet que tu utilises déjà ?!


RE: [JS]Invoquer dynamiquement une methode sur une class - Xenos - 13-08-2013

Citation :Prendre le cas ultime d'une erreur de programmeur pour en faire un argument c'est hors sujet.
J'ai pas compris.

"p_" préfixe les paramètres de toutes mes fonctions, tout langage confondu. L'intérêt est d'identifier immédiatement qu'une variable est un paramètre, et d'éviter les:
Code :
function nom(camelParam)
{
/*this.*/camelParam = /*parametre*/camelParam;
}
Mes classes démarrent par une majuscule, pour les distinguer des méthodes et variables, les deux respectant le camelCase. Mais, ok, j'ai zappé sur la variable "Usine" de fin de fichier; la faute à tropVite.

Je trouve les closures plus lisibles que prototype.
Comme indiqué:
Citation :j'aurai personnellement mis les gaz ailleurs que dans l'Usine elle-même

Mais bon, je peux toujours expliciter plus clairement:

function UsineAGaz(p_listeGaz)
{
var listeGaz = p_listeGaz;
this.produire = function(p_nom)
{
console.log('On me demande le gaz:',p_nom);
var ceGazCi = listeGaz['Gaz'+p_nom];
if (typeof ceGazCi == 'function')
return new ceGazCi();
console.warn('Le gaz "',p_nom,'" n\'existe pas.');
return new listeGaz.GazDefaut();
}
}
function ListeGaz()
{
this.GazXenon = function ()
{
this.saluer = function()
{
console.log('Je suis rare, donc précieux');
};
}
this.GazSchiste = function ()
{
this.saluer = function()
{
console.log('Je pue et je pollue !');
};
}
this.GazEau = function ()
{
this.saluer = function()
{
console.log('Y\'a de l\'eau dans le gaz.');
};
}
this.GazDefaut = this.GazEau;
}
var usine = new UsineAGaz( new ListeGaz() );
usine.produire('Eau').saluer();
usine.produire('pard').saluer();
usine.produire('Schiste').saluer();
usine.produire('Xenon').saluer();

Cela te plait mieux ainsi? Bon, ok, ca m'a couté 5 minutes, j'aurai pu (ou du) le faire dès le départ...


RE: [JS]Invoquer dynamiquement une methode sur une class - Maks - 13-08-2013

(13-08-2013, 04:30 PM)Xenos a écrit :
Citation :Prendre le cas ultime d'une erreur de programmeur pour en faire un argument c'est hors sujet.
J'ai pas compris.

Je soulignais simplement qu'on pouvait appeler n'importe qu'elle fonction d'un code Javascript depuis la console et tu me parles de faille XSS, quel rapport ? Je doute que Argorate passe sa variable de type par l'url et l'injecte dans le Javascript (ce qui me laisserait sans voix :cogneSmile

Citation :"p_" préfixe les paramètres de toutes mes fonctions, tout langage confondu. L'intérêt est d'identifier immédiatement qu'une variable est un paramètre, et d'éviter les:

Je connais cette notation, on la voit pas mal en Java. Mais dans ce cas on a pNom et non p_nom.

Citation : Mes classes démarrent par une majuscule, pour les distinguer des méthodes et variables, les deux respectant le camelCase. Mais, ok, j'ai zappé sur la variable "Usine" de fin de fichier; la faute à tropVite.

Hum d'accord, alors pour toi :

Code :
function ListeGaz()
{
    this.GazXenon = function () {};
}

GazXenon est une classe. Intéressant :heu:

Citation :Je trouve les closures plus lisibles que prototype.

Je vais faire comme toi, je vais ressortir le benchmarks Smile (qui marchent bien cependant cette fois-ci...).

C'est un peu mieux mais pas encore terrible le code.


RE: [JS]Invoquer dynamiquement une methode sur une class - niahoo - 13-08-2013

Vous avez donné la façon de faire dès le début, ensuite si une variable n'est pas accessible via window on se débrouille pour y accéder pis wala

Ben oui gaz xenon est une classe puisqu'il l'instancie avec new cegazci. D'ailleur il utilise bien new et pas des closures. Ah et le schiste c'est pascdu gaz les gars. Le gaz est dedans.




RE: [JS]Invoquer dynamiquement une methode sur une class - Maks - 13-08-2013

(13-08-2013, 04:56 PM)niahoo a écrit : Ben oui gaz xenon est une classe puisqu'il l'instancie avec new cegazci. D'ailleur il utilise bien new et pas des closures.

Il utilise new sur ce qui est censé être une closure, ça saute aux yeux quand même. Comme quoi ça choque plus personne de voir du JS fait n'importe comment :roll:

Un code acceptable imo :


GasList = {}

GasList.Xenon = function() {};
GasList.Xenon.prototype.greeting = function() {
console.log('Je suis rare, donc précieux');
};

GasList.Shale = function() {};
GasList.Shale.prototype.greeting = function() {
console.log('Je pue et je pollue !');
};

GasList.Water = function() {};
GasList.Water.prototype.greeting = function() {
console.log("Y'a de l'eau dans le gaz");
};

var GasFactory = function() {};
GasFactory.make = function(name) {
switch(name) {
case 'Xenon':
return new GasList.Xenon();
break;
case 'Shale':
return new GasList.Shale();
break;
case 'Water':
return new GasList.Water();
break;
default:
throw new TypeError(name + " class does not exists");
}
};

var xenon = GasFactory.make('Xenon');
var shale = GasFactory.make('Shale');
var water = GasFactory.make('Water');
xenon.greeting();
shale.greeting();
water.greeting();
var throwError = GasFactory.make('DoesNotExists');

Une solution plus rapide serait de tester l'existence de la clé dans l'objet Javascript (mais surtout pas comme Xenos l'a fait).