Создание динамических объектов - PullRequest
3 голосов
/ 10 июля 2010

У меня есть функция, которая принимает строковое имя объекта, и мне нужна функция для создания нового экземпляра объекта, имя которого совпадает со значением строки

Например,

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

Хотя я знаю, что это будет возможно через eval, было бы неплохо попробовать и избегать его использования.Мне также интересно, есть ли у кого-нибудь альтернативные идеи для проблемы (ниже)


У меня есть база данных и набор (с использованием классической методологии ОО) классов, примерно по одному для каждой таблицы, определяющей общие операциина этом столе.(Очень похоже на Zend_Db для тех, кто использует PHP).Поскольку все выполняется асинхронно, выполнение задач, основанных на результате последнего, может привести к появлению кода с очень большим отступом

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

Очевидным решением является создание вспомогательных методов, которые абстрагируют асинхронный характер кода.1013 *

Что упрощает вещи.Однако проблема в том, что мне нужно иметь возможность создавать классы таблиц, имена которых могут быть выведены из первого дополнения, переданного в require, что приводит меня к проблеме выше ...

Ответы [ 2 ]

4 голосов
/ 10 июля 2010

Почему бы просто не передать функцию конструктора в метод 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]();
}
2 голосов
/ 10 июля 2010

Вы были у ворот полноты.Хотя решение Аннабель позволяет вам делать то, что вы только что хотели, так, как вы хотели (передавая строки) , позвольте мне предложить вам альтернативу. (передача ссылок на функции)

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

И вуаля, это работает :) Я говорил вам.Вы были на пороге решения.

Что случилось, когда вы пытались сделать это

new 'Foo'()

Что не имеет особого смысла, не так ли?Но теперь вы передаете функцию по ссылке, поэтому строка return new name(); будет преобразована в return new Foo();, как вы и ожидаете.

И теперь двери открываются, чтобы абстрагировать асинхронность вашего приложения.Удачи!

Приложение: Функции являются первоклассными объектами , что означает, что они могут храниться по ссылке, передаваться в качестве аргумента по ссылке или возвращаться другой функцией в качестве значений.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...