2010-07-09 4 views
3

J'ai une fonction qui prend un nom d'objet chaîne et j'ai besoin de la fonction de créer une nouvelle instance d'un objet qui a le même nom que la valeur de la chaîneCréation d'objets dynamiques

Par exemple,

function Foo(){} 
function create(name){ 
    return new name(); 
} 
create('Foo'); //should be equivalent to new Foo(); 

Même si je sais que ce serait possible via eval, il serait bon d'essayer d'éviter de l'utiliser. Je suis également intéressé si quelqu'un a une des idées alternatives au problème (ci-dessous)


J'ai une base de données et un ensemble de (en utilisant la méthode OO classique) des classes, soit environ un pour chaque table qui définissent des opérations communes sur ce table. (Très similaire à Zend_Db pour ceux qui utilisent PHP). Comme tout est des tâches asynchrones faire en fonction du résultat du dernier peut conduire à code très échancré

var table1 = new Table1Db(); 
table1.doFoo({ 
    success:function(){ 
     var table2 = new Table2Db(); 
     table2.doBar({ 
      notFound:function(){ 
       doStuff(); 
      } 
     }); 
    } 
}); 

La solution évidente est de créer des méthodes d'aide que les résumés de la nature asynchrone du code.

Db.using(db) //the database object 
    .require('Table1', 'doFoo', 'success') //table name, function, excpected callback 
    .require('Table2', 'doBar', 'notFound') 
    .then(doStuff); 

Qui simplifie les choses. Cependant le problème est que je dois être capable de créer les classes de table, dont les noms peuvent être déduits de la première augmentation passé à require qui me conduit au problème ci-dessus ...

Répondre

4

Pourquoi ne pas simplement passer le constructeur fonctionner dans la méthode require? De cette façon, vous évitez toute la question de la conversion du nom à la fonction. Votre exemple serait alors ressembler à:

Db.using(db) //the database object 
    .require(Table1Db, 'doFoo', 'success') //table constructor, function name, expected callback 
    .require(Table2Db, 'doBar', 'notFound') 
    .then(doStuff); 

Cependant, si vous voulez vraiment utiliser une chaîne ...

Pourquoi êtes-vous DEADSET à éviter l'utilisation eval? C'est un outil dans la langue et chaque outil a son but (tout comme chaque outil peut être mal utilisé). Si vous souhaitez autoriser une exécution arbitraire, un simple test d'expression régulière devrait sécuriser votre utilisation.

Si vous êtes mort mis à éviter eval et si toutes les fonctions de votre constructeur sont créés dans la portée globale par défaut (par exemple l'objet de la fenêtre), cela fonctionnerait:

function create(name) { 
    return new window[name](); 
} 

Si vous voulez obtenir des objets d'espace de noms de fantaisie et de soutien (c.-à-create('MyCompany.MyLibrary.MyObject'), vous pouvez faire quelque chose comme ceci:

function create(name) { 
    var current, 
     parts, 
     constructorName; 

    parts = name.split('.'); 
    constructorName = parts[parts.length - 1]; 
    current = window; 
    for (var i = 0; i < parts.length - 1; i++) { 
    current = current[parts[i]]; 
    } 

    return new current[constructorName](); 
} 
+1

D'abord, merci pour la réponse. Comme toujours après avoir regardé une réponse, je me sens un peu stupide d'avoir raté des choses (rétrospectivement assez évidentes). Dans ce cas, les chaînes sont plus faciles, mais en passant le constructeur (quelque chose que je ne savais pas que l'on pouvait faire de cette façon) semble légèrement plus clair et plus clair. Je ne suis pas complètement opposé à l'utilisation d'eval, et comme vous le dites, il a sa place, cependant l'expérience m'a appris que si je pense que je dois l'utiliser 99% du temps je ne comprends pas assez la langue. (C'est l'une de ces fois). – Yacoby

+0

@Yacoby bien dit! :) Surtout les dernières phrases. J'aimerais que tout le monde pense de cette façon. – galambalazs

+0

C'était une bonne réponse. J'ai appris quelque chose de nouveau sur javascript! Merci :) – rossipedia

2

vous étiez à la porte de l'exhaustivité Alors que de la let solution de Annabelle vous faites ce que vous est avez juste voulu la manière que vous vouliez. (passant des chaînes), laissez-moi vous offrir une alternative. (références de fonction) passant

function Foo(){} 
function create(name){ 
    return new name(); 
} 
create(Foo); // IS equivalent to new Foo(); 

Et le tour est joué, il fonctionne :) Je vous ai dit. Vous étiez aux portes de la solution.

Qu'est-il arrivé est que vous avez essayé de le faire

new 'Foo'() 

Ce qui ne fait beaucoup de sens, il le fait? Mais maintenant vous passez la fonction par référence de sorte que la ligne return new name(); sera transformée en return new Foo(); juste comment vous vous attendriez.

Et maintenant les portes sont ouvertes pour faire abstraction de l'asynchronisme de votre application. S'amuser!

Annexe: Les fonctions sont des objets de première classe, ce qui signifie qu'elles peuvent être stockées par référence, passées en argument par référence ou renvoyées par une autre fonction en tant que valeurs.

+0

Les deuxième et troisième paramètres de 'require()' doivent toujours être des chaînes, les objets qu'ils identifient sont des propriétés d'objets qui n'existent pas encore. – Annabelle

+0

Oui, vous avez raison. – galambalazs

Questions connexes