2016-01-07 3 views
17

Ich möchte in der Lage sein, eine bestimmte ES6-Klasse zu instanziieren, indem Sie eine String-Variable an eine Funktion übergeben. Abhängig vom Wert der Variablen wird eine andere Klasse erstellt.Erstellen Sie eine Instanz einer Klasse in ES6 mit einem dynamischen Namen?

Beispiel - Ich habe 2 Klassen, ClassOne, ClassTwo. Ich möchte in der Lage sein, eine Variable an eine Funktion zu übergeben und eine neue Klasse zurück zu bekommen. Der Name der Klasse wird auf die Variable bezogen - z. Passing 'Two' wird ClassTwo erstellen.

ich nicht will nur verwenden, um eine switch Klausel wie folgt aus: mit dem Variablennamen

function createRelevantClass(desiredSubclassName) 
{ 
    let args = [], 
     newClass; 

    switch(desiredSubclassName) 
    { 
    case 'One' : 
     newClass = new ClassOne(args); 
     break; 
    case 'Two' : 
     newClass = new ClassTwo(args); 
     break; 
    } 

    return newClass; 
} 

Stattdessen möchte ich irgendwie in der Lage sein, den Konstruktoraufruf zu erstellen. Ist das möglich?

Antwort

19

Es gibt ein paar Möglichkeiten, können Sie dies erreichen können ...

1. Proxy-Klasse

Nach Im @ thefourtheye-Beispiel für die Verwaltung einer Zuordnung von Name zu Klasse könnten Sie eine Klasse haben, deren Aufgabe es ist, den Namen der gewünschten Klasse zu übernehmen und deren Instanziierung zu übernehmen:

[See it working]

Definieren Sie Ihre Klassen

// ClassOne.js 
export class ClassOne { 
    constructor() { 
     console.log("Hi from ClassOne"); 
    } 
} 

// ClassTwo.js 
export class ClassTwo { 
    constructor (msg) { 
     console.log(`${msg} from ClassTwo`); 
    } 
} 

Definieren Sie die Proxy-Klasse (z DynamicClass

)
import ClassOne from './ClassOne'; 
import ClassTwo from './ClassTwo'; 

// Use ES6 Object Literal Property Value Shorthand to maintain a map 
// where the keys share the same names as the classes themselves 
const classes = { 
    ClassOne, 
    ClassTwo 
}; 

class DynamicClass { 
    constructor (className, opts) { 
     return new classes[className](opts); 
    } 
} 

export default DynamicClass; 

Anwendungsbeispiel

import DynamicClass from './DynamicClass'; 

new DynamicClass('ClassOne'); //=> "Hi from ClassOne" 
new DynamicClass('ClassTwo', 'Bye'); //=> "Bye from ClassTwo" 

2. Fabrik Funktion

Verwenden Sie eine Funktion, die eine Lookup gegen ein Objekt der Klasse Namen führt - auf der> Klassenzuordnungen und liefert Referenz Klasse, die wir dann wie gewohnt instanziieren können.

Definieren Sie die Fabrik Funktion

import ClassOne from './ClassOne'; 
import ClassTwo from './ClassTwo'; 

const classes = { ClassOne, ClassTwo }; 

export default function dynamicClass (name) { 
    return classes[name]; 
} 

Anwendungsbeispiel

import dynamicClass from './dynamicClass' 

const ClassOne = dynamicClass('ClassOne') // Get the ClassOne class 

new ClassOne(args) // Create an instance of ClassOne 
+0

Ich mag diese, weil ich nicht explizit eine Karte von Variablen zu Klassen erstellen muss - nur eine Konstante mit der Gruppe von Klassen zu konstruieren ist genug. @ Thefourtheyes Beispiel ist ordentlich, aber ich denke, das ist näher an dem, was ich tun wollte. – raffjones

+6

Es muss eigentlich keine Klasse sein. Es kann eine einfache Fabrikfunktion sein. Eine Klasse ist irgendwie übertrieben IMHO. – thefourtheye

+0

@thefourtheye Ja, sicherlich nicht der einzige Weg. :-) – sdgluck

13

Speichern Sie die Klassen in einem Objekt, wobei die Schlüssel die Namen der Klassen sind, die sie haben sollen.

const classesMapping = { 
    'One': ClassOne, 
    'Two': ClassTwo 
}; 

dann die Klasse erstellen, die auf dem Schlüsselnamen basiert wie dieser

return new classesMapping[desiredSubclassName](args); 
+0

Aus Interesse, müssten die Klassen im selben Modul wie 'classesMapping' definiert werden? – CodingIntrigue

+0

@RGraham Nein. Nicht unbedingt. – thefourtheye

+1

Danke. Durchdacht und macht Sinn, dass es als Module irgendwann importiert werden müssten, z. https://plnkr.co/edit/luvxe81sIHQSwIyGwBdC?p=preview – CodingIntrigue

Verwandte Themen