如何使 ES6 class 最终版(非 subclassible)
How to make ES6 class final (non-subclassible)
假设我们有:
class FinalClass {
...
}
如何修改使
class WrongClass extends FinalClass {
...
}
或
new WrongClass(...)
生成异常?也许最明显的解决方案是在 FinalClass 的构造函数中执行以下操作:
if (this.constructor !== FinalClass) {
throw new Error('Subclassing is not allowed');
}
有没有人有更简洁的解决方案,而不是在每个 class 中重复这些行,这些行应该是最终的(可能使用装饰器)?
在FinalClass
的构造函数中检查this.constructor
,如果不是自己则抛出。 (从@Patrick Roberts 借用 this.constructor
而不是 this.constructor.name
的检查。)
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
或者,在支持下,使用 new.target
。谢谢@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
______
如您所说,您也可以使用装饰器实现此行为。
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
正如 Patrick Roberts 在评论中分享的那样,装饰器语法 @final
仍在提案中。它可用于 Babel 和 babel-plugin-transform-decorators-legacy.
constructor.name
很容易被欺骗。只需让子类与超类同名即可:
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!
}())
最好检查 constructor
本身:
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
}())
假设我们有:
class FinalClass {
...
}
如何修改使
class WrongClass extends FinalClass {
...
}
或
new WrongClass(...)
生成异常?也许最明显的解决方案是在 FinalClass 的构造函数中执行以下操作:
if (this.constructor !== FinalClass) {
throw new Error('Subclassing is not allowed');
}
有没有人有更简洁的解决方案,而不是在每个 class 中重复这些行,这些行应该是最终的(可能使用装饰器)?
在FinalClass
的构造函数中检查this.constructor
,如果不是自己则抛出。 (从@Patrick Roberts 借用 this.constructor
而不是 this.constructor.name
的检查。)
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
或者,在支持下,使用 new.target
。谢谢@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
______
如您所说,您也可以使用装饰器实现此行为。
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
正如 Patrick Roberts 在评论中分享的那样,装饰器语法 @final
仍在提案中。它可用于 Babel 和 babel-plugin-transform-decorators-legacy.
constructor.name
很容易被欺骗。只需让子类与超类同名即可:
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!
}())
最好检查 constructor
本身:
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
}())