Як зробити JavaScript-об'єкт за допомогою змінної String для визначення імені класу?


76

Ось що я намагаюся зробити - це псевдокод і не працює. Хтось знає, як це зробити по-справжньому:

// Define the class
MyClass = Class.extend({});

// Store the class name in a string
var classNameString = 'MyClass';

// Instantiate the object using the class name string
var myObject = new classNameString();

Відповіді:


68

Чи спрацювало б, якби ви зробили щось подібне:

var myObject = window[classNameString];

..?


Це спрацювало. peirix ти чудовий. Ви вважаєте, що це сумісно з переглядачами?
Kirk Ouimet 02

1
Думайте, ви мали на увазі window[classNameString](без цитат). Розбивається, як тільки MyClassпереміщується в нижчий (тобто function) обсяг. @kirk: так, це крос-браузер.
Crescent Fresh

1
Як ви передаєте аргументи конструктору, використовуючи цей метод?
James McMahon

3
@JamesMcMahon У такому випадку вам доведеться скористатися window[classNameString](args). Але, як згадує Crescent Fresh, будьте обережні, оскільки в деяких випадках це може зламатися.
peirix

8
Здається, це не працює для мене. Після декількох проб і помилок я виявив , що це працює: var obj = new Home(id);, але це не робить: var obj = new window["Home"](id);. Я намагаюся, щоб це спрацювало: new window[x](id);де x = "Home"... Помилка, яку я отримую,Uncaught TypeError: window[x] is not a constructor
Абрахам Мурчіано Бензадон

56

Ось більш надійне рішення, яке буде працювати з функціями з простором імен:

var stringToFunction = function(str) {
  var arr = str.split(".");

  var fn = (window || this);
  for (var i = 0, len = arr.length; i < len; i++) {
    fn = fn[arr[i]];
  }

  if (typeof fn !== "function") {
    throw new Error("function not found");
  }

  return  fn;
};

Приклад:

my = {};
my.namespaced = {};
(my.namespaced.MyClass = function() {
  console.log("constructed");
}).prototype = {
  do: function() {
    console.log("doing");
  }
};

var MyClass = stringToFunction("my.namespaced.MyClass");
var instance = new MyClass();
instance.do();

Чому (windows || this)вікно не завжди визначатиметься?
James McMahon

11
@JamesMcMahon: Світ, як ми знаємо, вже не є реальністю. Орендарі, такі як nodejs, також приїхали окупувати нашу планету! :)
Mrchief

Оскільки з’явився суворий режим ( ECMA-262, видання 5 у 2009 р.), Він window || thisможе повертатись невизначеним у не браузерному середовищі, якщо це не встановлено викликом (чого немає в прикладі).
RobG

Привіт, як використовувати це і змусити це працювати для класів, які імпортуються ?? Наприклад, імпортувати сітку з '../../mazes/components/Grid'
Престон

33

ДО: вікно - це посилання на глобальний об'єкт у JavaScript браузера. Що також є this, і повинно працювати навіть у не браузерних середовищах, таких як Node.js, розширення Chrome, переведений код тощо

var obj = new this[classNameString]();

Обмеження полягає в тому, що клас, який викликається, повинен знаходитись у глобальному контексті. Якщо ви хочете застосувати те саме до класу з обсягом, вам потрібно зробити:

var obj = (Function('return new ' + classNameString))()

Однак насправді немає причин використовувати рядок. Функції JavaScript самі по собі є об'єктами, як і рядки, які також є об'єктами.

Редагувати

Ось кращий спосіб отримати глобальну сферу, яка працює в суворому режимі, а також не-браузерні середовища JS:

var global;
try {
  global = Function('return this')() || (42, eval)('this');
} catch(e) {
  global = window;
}

// and then
var obj = new global[classNameString]

Від: Як отримати глобальний об’єкт у JavaScript?


9
Це лише за thisумови виклику з глобального контексту. windowпрацює незалежно від контексту ви перебуваєте, тому я не бачу ніяких причин віддавати перевагу thisбільш window.
devios1

4
Як і у відповідях, середовище, в якому ви перебуваєте, не обов’язково браузер. Тому використання thisпереважно, оскільки в не браузерному середовищі windowможе бути невизначено, або не те, що ви очікуєте.
Xedin Невідомо

@XedinUnknown Звичайно, коли ви пишете фрагмент JavaScript, ви знаєте, чи це для клієнта, чи, скажімо, для node. Якщо ви знаєте , що для браузера, то немає ніяких вад не надавати перевагу windowбільш this.
Себі,

2
@Sebi, ніде в питанні не мається на увазі, що середовище є клієнтським. Крім того, сторона клієнта також не обов’язково означає «браузер». Відповіді дають спосіб виконати вимоги ОП шляхом прямого посилання на глобальний контекст - у цьому вся суть. Я вказую, що єдиним надійним способом посилання на глобальний контекст із глобального є thisне window. Крім того, найбільш надійним способом посилання на глобальний контекст НЕ є глобальний контекст top. Крім того, можливо, добре ввести його в закриття.
Xedin Невідомо

1
@ devios1 Якщо ви протестуєте код, ви помітите, що він працює з будь-якого контексту, а не лише з глобального контексту. Ось чому ми робимо Function('return this')()замість return this. Перший автоматично перемикається на глобальний контекст. Це працює незалежно від контексту. вікно може бути перезаписано і призначене лише для браузера. Добре не знати контексту виконання коду, щоб писати крос-платформний код. Відповідь, яку я дав, є міжплатформою, і її неможливо перезаписати, і тому вона набагато краща за використання window. Він буде працювати у перекладеному коді, наприклад, з webpack, gulp, у вузлі, розширеннях тощо. Спершу протестуйте.
bucabay

12

Якщо MyClass глобальний, ви можете отримати доступ до нього як до властивості віконного об'єкта (за умови, що ваш код працює у браузері), використовуючи нотацію індексу.

var myObject = new window["MyClass"]();

Це працює у всіх браузерах? Я бачу, як деякі дописи скаржаться, що це не працює для них.
PHP Guru

9

Якщо ви classNameStringнадходите з безпечного джерела, ви можете використовувати його

var classNameString = 'MyClass';
var myObject = eval("new " + classNameString + "()");

Це рішення працює з просторами імен і не залежить від платформи (браузер / сервер).


3
Я не знаю про це і не знаю, чому його видалили?
Місаз,

1
@Jacksonkr, це також означає, що я не повинен пити пиво, бо це може стати шкідливою звичкою? :)
Vince Horst

3
За вашою аналогією: використовувати, evalколи ви чули, це погана ідея - це як їздити в нетверезому стані. "Нічого не сталося ... hic ... востаннє я водив алкоголь .. hic .. насправді я їду краще п'яним! ... hic ..." На той час, коли щось піде не так, вже пізно. Не будь таким хлопцем.
Jacksonkr

7
Забороняти НІКОЛИ використовувати функцію, eval чи іншу, просто погана порада. Якби це була функція без будь-яких випадків використання, вона б наразі амортизувалась і була б вилучена як функція.
MacroMan

1
Саме MacroMan. Видаляти його як відповідь смішно.
Lee

3

Ось покращена версія методу Юрія, який також обробляє об'єкти.

var stringToObject = function(str, type) {
    type = type || "object";  // can pass "function"
    var arr = str.split(".");

    var fn = (window || this);
    for (var i = 0, len = arr.length; i < len; i++) {
        fn = fn[arr[i]];
    }
    if (typeof fn !== type) {
        throw new Error(type +" not found: " + str);
    }

    return  fn;
};

0
function myClass(arg){
}

var str="myClass";
dynamic_class=eval(str);

var instance=new dynamic_class(arg); // OK

0

У Firefox існують правила безпеки для розширень, а також для консолі Javascript. Не робіть помилки, які я зробив при тестуванні в консолі, оскільки жодне з цих рішень не працює. Тоді як при тестуванні зі сторінки це працює краще:

  • рішення eval працює добре
  • Функція ('повернути нове' ... працює (об'єкт створюється), за винятком аргументів конструктора, які передаються як "невизначені". Я не тестував інших рішень.

Французькою мовою: Sur Firefox надає вам додаткові допоміжні розширення та додає до консолі Javascript. Ne faites pas l'erreur que j'ai faite de tester depuis la console car aucune de ces solutions ne marchent. Par contre quand on teste depuis une page cela fonctionne mieux:

  • la розчин eval fonctionne bien
  • Функція ('повернути нове' ... fonctionne (l'objet est créé) sauf que les paramètres du constructeur sont "undefined" Je n'ai pas testé les autres solutions.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.