我有一个带字符串对象名称的函数,我需要该函数来创建一个与字符串值相同的对象的新实例
例如,
function Foo(){}
function create(name){
return new name();
}
create('Foo'); //should be equivalent to new Foo();
虽然我知道这可以通过eval实现,但尝试避免使用它会很好。我也有兴趣,如果有人对问题有另一种想法(下面)
我有一个数据库和一组(使用经典的OO方法)类,每个表大约有一个用于定义该表上常见操作的表。 (对于那些使用PHP的人来说,非常类似于Zend_Db)。由于一切都是异步的,因此根据最后一个结果执行任务可能会导致非常缩进的代码
var table1 = new Table1Db();
table1.doFoo({
success:function(){
var table2 = new Table2Db();
table2.doBar({
notFound:function(){
doStuff();
}
});
}
});
显而易见的解决方案是创建辅助方法,以抽象代码的异步性质。
Db.using(db) //the database object
.require('Table1', 'doFoo', 'success') //table name, function, excpected callback
.require('Table2', 'doBar', 'notFound')
.then(doStuff);
简化了事情。然而问题是我需要能够创建表类,其名称可以从传递给require
的第一个扩充中推断出来,这导致我上面的问题......
答案 0 :(得分:4)
为什么不简单地将构造函数传递给require
方法?这样你就可以回避从名称转换为函数的整个问题。您的示例将如下所示:
Db.using(db) //the database object
.require(Table1Db, 'doFoo', 'success') //table constructor, function name, expected callback
.require(Table2Db, 'doBar', 'notFound')
.then(doStuff);
但是,如果你真的想使用字符串......
为什么你对避免使用eval
感到厌烦?它是语言中的工具,每个工具都有其目的(正如每个工具都可以被误用)。如果您担心允许任意执行,那么简单的正则表达式测试应该可以使您的使用安全。
如果您已经设置为避免eval
并且如果所有构造函数都是在默认的全局范围(即窗口对象)中创建的,那么这将起作用:
function create(name) {
return new window[name]();
}
如果你想获得幻想并支持命名空间对象(即create('MyCompany.MyLibrary.MyObject')
),你可以这样做:
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 :(得分:2)
你是完整的大门。虽然Annabelle的解决方案让你以你想要的方式做你想要的事情(传递字符串),让我为你提供另一种选择。 (传递函数引用)
function Foo(){}
function create(name){
return new name();
}
create(Foo); // IS equivalent to new Foo();
并且瞧,它有效 :)我告诉过你。你就在解决方案的门口。
发生了什么事,你试图这样做
new 'Foo'()
这没有多大意义,是吗?但现在您通过引用传递函数,因此行return new name();
将转换为return new Foo();
,就像您期望的那样。
现在打开门以抽象应用程序的异步性。玩得开心!
附录:函数是第一类对象,这意味着它们可以通过引用存储,通过引用作为参数传递或作为值返回给另一个函数。