2016-08-03 6 views
1

Angenommen, wir machen müssen:Wie ES6 Klasse final (non-subclassible)

class FinalClass { 
    ... 
} 

Wie es ändern, eine Ausnahme zu machen

class WrongClass extends FinalClass { 
    ... 
} 

oder

new WrongClass(...) 

zu erzeugen ? Vielleicht ist die naheliegendste Lösung ist die folgende im Konstruktor des FinalClass zu tun:

if (this.constructor !== FinalClass) { 
    throw new Error('Subclassing is not allowed'); 
} 

Hat jemand eine sauberere Lösung anstatt diese Zeilen in jeder Klasse zu wiederholen, dass (wahrscheinlich mit einem Dekorateur) endgültig sein soll?

+3

Interessante Frage. Gibt es einen Grund, warum du das versuchst? – gcampbell

+0

Da letztlich alles auf Javascript (<5) kompiliert ist, wo solche Dinge nicht existieren und alles nur ein Objekt ist, das zur Laufzeit unendlich formbar ist, halte ich die Chancen dafür für schlecht. – deceze

+0

Um den von @gcampbell implizierten Punkt stärker zu formulieren, erscheint mir das als eine schlechte Idee, grenzend an schrecklich. Zum Beispiel saugen Zeichenketten in Java keinen kleinen Teil, weil der Klasse viele nützliche Methoden fehlen und wurde als vorzeitige Leistung hack "endgültig". –

Antwort

6

Inspizieren Sie this.constructor im Konstruktor FinalClass und werfen Sie, wenn es nicht selbst ist. (Borrowing Inspektion der this.constructor statt this.constructor.name von @Patrick Robert.)

class FinalClass { 
 
    constructor() { 
 
    if (this.constructor !== FinalClass) { 
 
     throw new Error('Subclassing is not allowed') 
 
    } 
 
    console.log('Hooray!') 
 
    } 
 
} 
 

 
class WrongClass extends FinalClass {} 
 

 
new FinalClass() //=> Hooray! 
 

 
new WrongClass() //=> Uncaught Error: Subclassing is not allowed

Alternativ mit Unterstützung, new.target verwenden. Danke @loganfsmyth.

class FinalClass { 
 
    constructor() { 
 
    if (new.target !== FinalClass) { 
 
     throw new Error('Subclassing is not allowed') 
 
    } 
 
    console.log('Hooray!') 
 
    } 
 
} 
 

 
class WrongClass extends FinalClass {} 
 

 
new FinalClass() //=> Hooray! 
 

 
new WrongClass() //=> Uncaught Error: Subclassing is not allowed

______

Wie Sie sagen, können Sie auch dieses Verhalten mit einem Dekorateur erreichen.

function final() { 
 
    return (target) => class { 
 
    constructor() { 
 
     if (this.constructor !== target) { 
 
     throw new Error('Subclassing is not allowed') 
 
     } 
 
    } 
 
    } 
 
} 
 

 
const Final = final(class A {})() 
 

 
class B extends Final {} 
 

 
new B() //=> Uncaught Error: Subclassing is not allowed

Als Patrick Roberts in den Kommentaren ist der Dekorateur Syntax @final geteilt noch in Vorschlag. Es ist verfügbar mit Babel und babel-plugin-transform-decorators-legacy.

+2

Oder noch besser, wenn Sie nicht transpilieren und Unterstützung dafür haben, tun Sie "new.target! == target", und Sie vermeiden den Kantenfall, dass 'this.constructor' neu zugewiesen werden könnte. – loganfsmyth

+1

@loganfsmyth 'new.target' ist auch nicht narrensicher, z.B. 'Reflect.construct (WrongClass, [], FinalClass)' – Oriol

3

constructor.name ist einfach genug zu spoof. So stellen Sie die Unterklasse die gleichen Namen wie die übergeordneten Klasse:

class FinalClass { 
 
    constructor() { 
 
    if (this.constructor.name !== 'FinalClass') { 
 
     throw new Error('Subclassing is not allowed') 
 
    } 
 
    console.log('Hooray!') 
 
    } 
 
} 
 

 
const OopsClass = FinalClass 
 

 
;(function() { 
 
    class FinalClass extends OopsClass {} 
 

 
    const WrongClass = FinalClass 
 

 
    new OopsClass //=> Hooray! 
 

 
    new WrongClass //=> Hooray! 
 
}())

besser zu überprüfen, die constructor selbst:

class FinalClass { 
 
    constructor() { 
 
    if (this.constructor !== FinalClass) { 
 
     throw new Error('Subclassing is not allowed') 
 
    } 
 
    console.log('Hooray!') 
 
    } 
 
} 
 

 
const OopsClass = FinalClass 
 

 
;(function() { 
 
    class FinalClass extends OopsClass {} 
 

 
    const WrongClass = FinalClass 
 

 
    new OopsClass //=> Hooray! 
 

 
    new WrongClass //=> Uncaught Error: Subclassing is not allowed 
 
}())

+0

'// => Hurra! :-) ' – sdgluck

+0

Während dies technisch korrekt ist, sind die falsch platzierten Semikola und das Fehlen von Parens mit' new' nicht wirklich Praktiken, die gefördert werden sollten. Beide machen den Code im besten Fall zweideutig und können leicht beschädigt werden, wenn Sie ihn neu anordnen. – ssube

+2

@ssube Das Fehlen von Parens mit 'new' ist ärgerlich (' neues Foo.bar() 'vs' neues Foo(). Bar() '), aber semikolon-less Stil Ich sorge mich nicht um zu korrigieren; (Wortspiel beabsichtigt) Es wird in großen Projekten (z. B. npm) verwendet und es gibt 33.00000000000004 andere Dinge, über die man sich in JS beschweren kann. (Flammenkrieg folgt) – gcampbell