JavaScript, Eval и New - фабрика для бедняков - PullRequest
3 голосов
/ 06 июля 2011

За исключением редких случаев, eval () считается плохой практикой в JavaScript.

Я только что натолкнулся на фрагмент кода, который принимает строку и создает объект этого типаназвание.Проверка ошибок, бизнес-логика и контекст для этого удалены, вот как это выглядит:

function factory(klass) {
  eval("var obj = new " + klass + "()"); // Is there a better way?
  return obj;
}

Есть ли лучший (более безопасный, чище и / или быстрее) способ создания класса без использования eval ?

Я ищу универсальный способ создания класса по его имени .

например,Представьте, например, что другая часть кода динамически загружает файлы JavaScript, генерирует код или разрешает пользовательские расширения, но затем какая-то другая часть кода должна создать этот класс без предварительной информации о существовании фабрики.

Ответы [ 3 ]

5 голосов
/ 06 июля 2011

Вы можете зарегистрировать классы с помощью объекта фабрики, а затем создать их по строковому имени:

var allClasses = [];
allClasses["MyClass"] = function(){return new MyClass();}
allClasses["MyStruct"] = function() {return {F1:"", F2:42};}

function factory(klass) 
{
    if (!allClasses[klass]) throw "Bad name!";
    return allClasses[klass]();
}
3 голосов
/ 06 июля 2011

Вот ситуация, когда проверка ошибок важна, и вы не должны были ее удалять. Скажем, мы идем с «трудным фабричным» решением @ Gabi:

function hardfactory(klass) {
  var obj = new klass();
  return obj;
}

try {
var x = hardfactory(asdf); // this will break unless
                           // we wrap every single hardfactory() call in a try-catch
} catch (err) {
    console.log(err);
} // who wants to do this every time we invoke hardfactory? not I

Теперь давайте рассмотрим ваше оригинальное решение "soft factory":

function softfactory(klass) {
  try {
      eval("var obj = new " + klass + "()");
  } catch (err) {
      console.log(err);
  }
  return obj;
}

var y = softfactory("asdf"); // this will not break
                             // since we do the try catch inside the softfactory()

В этом случае вызов eval() вполне оправдан. Важно понимать, что каждая языковая конструкция (да, даже eval()) полезна и является частью языка по определенной причине. Тот факт, что некоторые люди злоупотребляют им или используют его в неправильных обстоятельствах, не означает, что это не очень мощный инструмент в правильных.

1 голос
/ 06 июля 2011

Вам не нужно eval.Вы можете просто передать объект вместо его имени и использовать var obj = new klass().Вуаля

function factory(klass) {
  var obj = new klass();
  return obj;
}

function C() {...}
C.prototype = {...}

factory(C);
...