ECMAScript 6是否有抽象类的约定?

196

当我在研究ES6时,惊讶地发现没有关于抽象类的内容。(我所说的“抽象类”是指Java中的概念,即抽象类声明方法签名,子类必须实现这些方法才能被实例化)

有人知道在ES6中已经出现了哪些惯例来实现抽象类吗?能够通过静态分析捕获抽象类违规将是很好的。

如果我在运行时引发一个错误来表示对抽象类进行实例化的尝试,那么错误会是什么?


5
ES6并没有改变早期JavaScript版本基本的原型继承机制。在JavaScript中,“抽象类”的概念并不是很合理,尽管预处理类型的语言可以实现这样一种东西。 - Pointy
1
由于JavaScript不是强类型语言,因此抽象类并不实用。 - gorgi93
1
抽象类,连同特质和混入,是一个待定的提案(“稻草人”),详情请见此链接。其中包括了为类进行特质组合的提案。 - Jonathan Lonowski
6
抽象类与强类型并没有关联。像 Smalltalk 这样的动态类型语言自20世纪70年代以来就一直有抽象类(按照惯例)。 - obelia
2
(晚来一步)我会支持你,认为这不是一个重复的问题。即使它们在底层是相同的,但这个问题经常被问到。JS类与Ruby类有些相似。我使用了类似的方法来抛出错误,如果某些东西没有实现,但不检查实例化(许多Ruby开发人员也这样做)。在我看来,这是清晰的代码。创建一个NotImplementedClass (第二个答案)。然后在你的基类中 mymethod(){throw new NotImplementedError()} - Matthew Pautzke
显示剩余4条评论
1个回答

368

ES2015没有像Java那样内置支持您期望的设计模式的类。但是,它有一些选项可能会有所帮助,具体取决于您要完成的任务。

如果您想要一个无法构造但其子类可以构造的类,则可以使用new.target

ES2015没有Java风格的类,无法直接创建符合你期望设计模式的类。不过,根据你具体想要实现的功能,它提供了一些可行的选择。

如果你需要一个无法被构建的类,但它的子类可以被构建,那么你可以使用new.target

class Abstract {
  constructor() {
    if (new.target === Abstract) {
      throw new TypeError("Cannot construct Abstract instances directly");
    }
  }
}

class Derived extends Abstract {
  constructor() {
    super();
    // more Derived-specific stuff here, maybe
  }
}

const a = new Abstract(); // new.target is Abstract, so it throws
const b = new Derived(); // new.target is Derived, so no error

了解更多关于new.target的细节,请阅读关于ES2015类如何工作的一般概述:http://www.2ality.com/2015/02/es6-classes-final.html

如果您特别需要确保实现某些方法,也可以在超类构造函数中检查:

class Abstract {
  constructor() {
    if (this.method === undefined) {
      // or maybe test typeof this.method === "function"
      throw new TypeError("Must override method");
    }
  }
}

class Derived1 extends Abstract {}

class Derived2 extends Abstract {
  method() {}
}

const a = new Abstract(); // this.method is undefined; error
const b = new Derived1(); // this.method is undefined; error
const c = new Derived2(); // this.method is Derived2.prototype.method; no error

28
谢谢。但我不认为你应该将这个标记为重复问题,因为1)这是一个不同的问题;2)另一个问题的被接受答案是错误的答案,不能回答我的问题;3)我的问题先被提出来了。我看到AWB在另一个问题中的答案也回答了我的问题,但它没有被标记为被接受的答案。 - obelia
7
刚刚发现Safari不支持new.target,转换后的代码会抛出错误:SyntaxError: Unexpected token '.' - siannone
1
截至2016年4月29日,最新的Babel已支持new.target:https://github.com/babel/babel-eslint/issues/235 - Sámal Rasmussen
1
@siannone MDN 表示 Safari 支持 new.target。https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/new.target#Browser_compatibility - Jacob Phillips
4
如果您编写 throw new TypeError("Cannot construct " + new.target.name + " instances directly");,它将更加易于重构。 - Waruyama
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接