Wie erstelle ich ein JavaScript-Objekt mit einer Variablen String, um den Klassennamen zu definieren?

76

Folgendes versuche ich zu tun - dies ist Pseudocode und funktioniert nicht. Weiß jemand, wie man das wirklich erreicht:

// 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();
Kirk Ouimet
quelle

Antworten:

66

Würde es funktionieren, wenn Sie so etwas tun würden:

var myObject = window[classNameString];

..?

Peirix
quelle
Das hat funktioniert. Peirix, du bist großartig. Sie denken, es ist browserübergreifend kompatibel?
Kirk Ouimet
1
Denke du meintest window[classNameString](keine Anführungszeichen). Bricht ab, sobald MyClassein niedrigerer (dh function) Bereich erreicht wird. @ Kirk: Ja, das ist Cross-Browser.
Crescent Fresh
1
Wie übergeben Sie mit dieser Methode Argumente an den Konstruktor?
James McMahon
3
@ JamesMcMahon In diesem Fall müssten Sie verwenden window[classNameString](args). Aber wie Crescent Fresh erwähnt, seien Sie vorsichtig, da dies in einigen Fällen brechen kann.
Peirix
8
Das scheint bei mir nicht zu funktionieren. Nach einigem Ausprobieren stellte ich fest, dass dies funktioniert: var obj = new Home(id);aber das funktioniert nicht : var obj = new window["Home"](id);. Ich versuche, dies zum new window[x](id);x = "Home"Uncaught TypeError: window[x] is not a constructor
Laufen
56

Hier ist eine robustere Lösung, die mit Funktionen mit Namespace funktioniert:

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;
};

Beispiel:

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();
Yuriy Nemtsov
quelle
Warum (windows || this)wird das Fenster nicht immer definiert?
James McMahon
11
@ JamesMcMahon: Die Welt, wie wir sie kennen, ist nicht mehr die Realität. Mieter wie Nodejs sind auch gekommen, um unseren Planeten zu besetzen! :)
Mrchief
Da der strikte Modus eingeführt wurde ( ECMA-262 ed 5 in 2009), window || thiskann er in einer Umgebung ohne Browser undefiniert zurückgegeben werden, wenn dies nicht durch den Aufruf festgelegt wurde (was im Beispiel nicht der Fall ist).
RobG
Hallo, wie man das benutzt und es für Klassen funktioniert, die importiert werden? zB Import Grid von '../../mazes/components/Grid'
Preston
33

Übrigens: Fenster ist der Verweis auf das globale Objekt in Browser-JavaScript. Das ist auch thisund sollte auch in Nicht-Browser-Umgebungen wie Node.js, Chrome-Erweiterungen, transpiliertem Code usw. funktionieren.

var obj = new this[classNameString]();

Die Einschränkung besteht darin, dass sich die aufgerufene Klasse im globalen Kontext befinden muss. Wenn Sie dasselbe auf eine Klasse mit Gültigkeitsbereich anwenden möchten, müssen Sie Folgendes tun:

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

Es gibt jedoch wirklich keinen Grund, eine Zeichenfolge zu verwenden. JavaScript-Funktionen sind selbst Objekte, genau wie Zeichenfolgen, die auch Objekte sind.

Bearbeiten

Hier ist ein besserer Weg, um den globalen Bereich zu erhalten, der sowohl im strengen Modus als auch in JS-Umgebungen ohne Browser funktioniert:

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

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

Von: Wie erhalte ich das globale Objekt in JavaScript?

bucabay
quelle
9
Es ist nur, thiswenn aus einem globalen Kontext aufgerufen. windowarbeitet unabhängig vom Kontext Sie sind, so dass ich keinen Grund zu bevorzugen sehen thisüber window.
Devios1
4
Wie in der Antwort angegeben, ist die Umgebung, in der Sie sich befinden, nicht unbedingt ein Browser. Daher ist die Verwendung thisvorzuziehen, da in einer Umgebung ohne Browser windowmöglicherweise nicht definiert ist oder nicht den Erwartungen entspricht.
XedinUnknown
@XedinUnknown Wenn Sie ein Stück Javascript schreiben, wissen Sie normalerweise, ob es für den Client oder beispielsweise für den Knoten ist. Wenn Sie es für einen Browser wissen, dann gibt es keine Nachteile bevorzugen windowüber this.
Sebi
2
@Sebi, nirgends in der Frage wird impliziert, dass die Umgebung clientseitig ist. Außerdem bedeutet clientseitig nicht unbedingt "Browser". Die Antworten bieten eine Möglichkeit, die Anforderungen des OP zu erfüllen, indem explizit auf den globalen Kontext verwiesen wird - das ist der springende Punkt. Ich weise darauf hin, dass der einzig verlässliche Weg, den globalen Kontext aus dem globalen Kontext heraus zu referenzieren this, nicht ist window. Darüber hinaus ist der zuverlässigste Weg, den globalen Kontext NICHT aus dem globalen Kontext heraus zu referenzieren, der top. Vielleicht auch gut, um es in den Verschluss zu injizieren.
XedinUnknown
1
@ devios1 Wenn Sie den Code testen, werden Sie feststellen, dass er in jedem Kontext funktioniert, nicht nur im globalen Kontext. Deshalb machen wir Function('return this')()statt return this. Ersteres wechselt automatisch in den globalen Kontext. Dies funktioniert unabhängig vom Kontext. Fenster kann überschrieben werden und ist nur Browser. Es ist gut, den Kontext der Codeausführung nicht zu kennen, um plattformübergreifenden Code zu schreiben. Die Antwort, die ich gegeben habe, ist plattformübergreifend und kann nicht überschrieben werden und ist daher viel besser als die Verwendung window. Es funktioniert in transpiliertem Code, wie mit Webpack, Gulp und in Knoten, Erweiterungen usw. Bitte testen Sie es zuerst.
Bucabay
12

Wenn MyClass global ist, können Sie als Eigenschaft eines Fensterobjekts (vorausgesetzt, Ihr Code wird in einem Browser ausgeführt) unter Verwendung der tiefgestellten Notation darauf zugreifen.

var myObject = new window["MyClass"]();
Chetan S.
quelle
Funktioniert das in allen Browsern? Ich sehe einige Beiträge, die sich beschweren, dass es für sie nicht funktioniert.
PHP Guru
9

Wenn Sie classNameStringaus einer sicheren Quelle stammen, können Sie diese verwenden

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

Diese Lösung funktioniert mit Namespaces und ist plattformunabhängig (Browser / Server).

Misaz
quelle
3
Ich weiß nichts darüber und weiß nicht, warum es gelöscht wurde?
Misaz
1
@Jacksonkr, heißt das auch, dass ich überhaupt kein Bier trinken sollte, weil es zu einer schlechten Angewohnheit werden kann? :)
Vince Horst
3
Gemäß Ihrer Analogie: evalWenn Sie gehört haben, dass es eine schlechte Idee ist, ist das wie betrunken zu fahren. "Nichts ist passiert ... hic ... das letzte Mal, als ich Alkohol gefahren bin ... hic ... tatsächlich fahre ich besser betrunken! ... hic ..." Bis etwas schief geht, ist es zu spät. Sei nicht dieser Typ.
Jacksonkr
7
NIEMALS eine Funktion zu verwenden, sei es eine Bewertung oder eine andere, ist nur ein schlechter Rat. Wenn es sich um eine Funktion ohne Anwendungsfälle handelte, wurde sie inzwischen abgeschrieben und als Feature entfernt.
MacroMan
1
Genau MacroMan. Es ist lächerlich, es als Antwort zu löschen.
Lee
3

Hier ist eine verbesserte Version von Yuriys Methode, die auch Objekte behandelt.

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;
};
pjesi
quelle
0
function myClass(arg){
}

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

var instance=new dynamic_class(arg); // OK
Xakiru
quelle
0

In Firefox gibt es Sicherheitsregeln für Erweiterungen und damit für die Javascript-Konsole. Machen Sie nicht den Fehler, den ich beim Testen in der Konsole gemacht habe, da keine dieser Lösungen funktioniert. Wenn Sie von einer Seite aus testen, funktioniert dies besser:

  • Die Eval-Lösung funktioniert gut
  • Funktion ('return new' ... funktioniert (Objekt wird erstellt) mit Ausnahme der Argumente des Konstruktors, die als "undefiniert" übergeben werden. Ich habe keine anderen Lösungen getestet.

Auf Französisch: Sur Firefox il ya des règles de sécurité qui s'appliquent aux extensions und donc à la console 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 Lösung eval fonctionne bien
  • Funktion ('return new' ... fonctionne (l'objet est créé) sauf que les paramètres du constructeur sont "undefined" Je n'ai pas testé les autres solutions.
Antonius
quelle