2015-08-02 11 views
7

Chcę utworzyć fabrykę obiektów przy użyciu ES6, ale składnia w starym stylu nie działa z nowymi.Utwórz obiekt z łańcucha znaków w JavaScriptScript ECMAScript 6

mam następny kod:

export class Column {} 
export class Sequence {} 
export class Checkbox {} 

export class ColumnFactory { 
    constructor() { 
     this.specColumn = { 
      __default: 'Column', 
      __sequence: 'Sequence', 
      __checkbox: 'Checkbox' 
     }; 
    } 

    create(name) { 
     let className = this.specColumn[name] ? this.specColumn[name] : this.specColumn['__default']; 
     return new window[className](name); // this line throw error 
    } 
} 

let factory = new ColumnFactory(); 
let column = factory.create('userName'); 

Co robię źle?

+0

Twojej wiadomości, ręcznie kodowane wersja ES5 tego pracuje tutaj: http: // jsfiddle. net/jfriend00/4x45gqLt /. Prawdopodobnie warto przyjrzeć się, co produkuje babeljs, aby zobaczyć, co jest inne. Podobno 'Column' nie jest globalna (a więc nie jest obiektem' window'), ale wygenerowany kod ES5 pokaże ci na pewno. – jfriend00

+0

Um, 'window [className]' nigdy nie działało niezawodnie. – Bergi

Odpowiedz

6

Nie umieszczaj nazw klas na tym obiekcie. Umieść tam same zajęcia, abyś nie musiał polegać na ich globalności i dostępności (w przeglądarkach) poprzez window.

Btw, nie ma żadnego powodu, aby uczynić fabrykę klasą, prawdopodobnie powstałbyś tylko raz (singleton). Po prostu zrób to obiekt:

export class Column {} 
export class Sequence {} 
export class Checkbox {} 

export const columnFactory = { 
    specColumn: { 
     __default: Column, // <-- 
     __sequence: Sequence, // <-- 
     __checkbox: Checkbox // <-- 
    }, 
    create(name, ...args) { 
     let cls = this.specColumn[name] || this.specColumn.__default; 
     return new cls(...args); 
    } 
}; 
3

Problem polega na tym, że klasy nie są właściwościami obiektu okna. Możesz mieć obiekt z właściwościami "wskazującymi" zamiast swoich klas:

class Column {} 
class Sequence {} 
class Checkbox {} 
let classes = { 
    Column, 
    Sequence, 
    Checkbox 
} 

class ColumnFactory { 
    constructor() { 
     this.specColumn = { 
      __default: 'Column', 
      __sequence: 'Sequence', 
      __checkbox: 'Checkbox' 
     }; 
    } 

    create(name) { 
     let className = this.specColumn[name] ? this.specColumn[name] : this.specColumn['__default']; 
     return new classes[className](name); // this line no longer throw error 
    } 
} 

let factory = new ColumnFactory(); 
let column = factory.create('userName'); 

export {ColumnFactory, Column, Sequence, Checkbox}; 
+0

Czy konstruktor 'Column' nie jest globalny? – jfriend00

+0

Najwyraźniej nie w babeljs (nie można opublikować ponownie, zbyt długo) – Amit

0

Dla tych z Was, które nie są używane ES6 i chcą wiedzieć, w jaki sposób można utworzyć klasy przy użyciu ciąg Oto co mam zrobić, aby to działało.

"use strict"; 

class Person { 
    constructor(x, y) { 
     this.x = x; 
     this.y = y; 
    } 
} 
window.classes = {}; 
window.classes.Person = Person; 

document.body.innerText = JSON.stringify(new window.classes["Person"](1, 2)); 

Jak widać najprostszym sposobem na to jest dodanie klasy do obiektu.

Oto skrzypce: https://jsfiddle.net/zxg7dsng/1/

Oto projekt przykład, który używa tego podejścia: https://github.com/pdxjohnny/dist-rts-client-web

4

Jest mała & brudny sposób, aby to zrobić:

function createClassByName(name,...a) { 
    var c = eval(name); 
    return new c(...a); 
} 

Ty można teraz utworzyć taką klasę:

let c = createClassByName('Person', x, y); 
+0

Podoba mi się to rozwiązanie eval – johnlowvale

0

wolę tę metodę:

allThemClasses.js

export class A {} 
export class B {} 
export class C {} 

script.js

import * as Classes from './allThemClasses'; 

const a = new Classes['A']; 
const b = new Classes['B']; 
const c = new Classes['C']; 
Powiązane problemy