【问题标题】:Dynamic Object Creation动态对象创建
【发布时间】:2010-07-09 22:15:10
【问题描述】:

我有一个接受字符串对象名称的函数,我需要该函数来创建一个与字符串值同名的对象的新实例

例如,

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 的第一个扩充中推断出来,这导致我遇到上述问题...

【问题讨论】:

    标签: javascript dynamic object


    【解决方案1】:

    为什么不简单地将构造函数传递给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]();
    }
    

    【讨论】:

    • 首先,感谢您的回复。与往常一样,在查看答案后,我因为错过了一些(回想起来相当明显)的事情而感到有点愚蠢。在这种情况下,字符串更容易,但是传递构造函数(我不知道可以以这种方式完成)看起来更简洁,更重要的是清晰。我并不坚决反对使用 eval,正如你所说,它有它的位置,但是经验告诉我,如果我认为我需要在 99% 的时间使用它,我对语言的理解不够好。 (这是其中之一)。
    • @Yacoby 说得好! :) 尤其是最后几句话。我希望每个人都能这样想。
    • 这是一个很好的答案。学到了一些关于 javascript 的新知识!谢谢:)
    【解决方案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();

    现在,抽象应用程序的异步性的大门打开了。玩得开心!

    附录:函数是一等对象,这意味着它们可以通过引用存储,通过引用作为参数传递或由另一个函数作为值返回。

    【讨论】:

    • require() 的第二个和第三个参数仍然必须是字符串,它们标识的对象是尚不存在的对象的属性。
    猜你喜欢
    • 2012-09-07
    • 1970-01-01
    • 2020-10-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-09
    相关资源
    最近更新 更多