如何在 JavaScript 中创建无法实例化的抽象基类
Posted
技术标签:
【中文标题】如何在 JavaScript 中创建无法实例化的抽象基类【英文标题】:How to create Abstract base class in JavaScript that can't be Instantiated 【发布时间】:2015-08-14 01:40:55 【问题描述】:我有课
function Node()
//implementation
和另一个班级
function AttributionalNode()
this.prototype.setAttr = function (attr)
this.atText = attr;
;
AttributionalNode.prototype = new Node();
AttributionalNode.prototype.constructor = AttributionalNode;
如何使类 Node() 不能被实例化? 例如,当我尝试时
var node = new Node();
所以它抛出一个异常?
【问题讨论】:
把throw new Exception()
放在构造函数中,也许吧?我不知道这在 javascript 中是否有效。
一般来说,在构造函数中设置原型属性并不是一个好主意。
【参考方案1】:
在支持 ECMAScript 2015(又名 ES6)类语法的 JavaScript 引擎中,这可以使用 new.target
元属性来完成:
function Node()
if (new.target === Node) throw TypeError("new of abstract class Node");
或使用类语法:
class Node
constructor ()
if (new.target === Node) throw TypeError("new of abstract class Node");
在任何一种情况下,只需将AttributionalNode
定义为:
class AttributionalNode extends Node
constructor ()
super();
setAttr(attr)
this.atText = attr;
new Node(); // will throw TypeError
new AttributionalNode(); // works fine
有关new.target
的更详细说明,请参阅this document 的第4.2 节。
【讨论】:
可以提供new.target
的参考吗?
如果您想知道它是否支持:kangax.github.io/compat-table/es6/#new.target。如上所述,目前不支持。
MDN: new.target
new.target
和this.constructor
有区别吗?【参考方案2】:
这可行:
function Node()
if (this.constructor === Node)
throw new Error("Cannot instantiate this class");
function AttributionalNode()
Node.call(this); // call super
AttributionalNode.prototype = Object.create(Node.prototype);
AttributionalNode.prototype.setAttr = function (attr)
this.atText = attr;
;
AttributionalNode.prototype.constructor = AttributionalNode;
var attrNode = new AttributionalNode();
console.log(attrNode);
new Node();
注意:你不能在构造函数中引用this.prototype
,因为原型只是构造函数的属性,而不是实例的属性。
另外,see here 有一篇关于如何正确扩展 JS 类的好文章。
【讨论】:
某个类尝试从Node()继承时报错 @AlexandrSargsyan 它没有。我更新了示例来演示这一点。【参考方案3】:调整@levi 的答案,您可以使用类似的解决方案来与今天的 ES6 一起使用(因为 new.target
尚未建立):
你可以看到它在 Babel 的 repl 上运行:http://bit.ly/1cxYGOP
class Node
constructor ()
if (this.constructor === Node)
throw new Error("Cannot instantiate Base Class");
callMeBaby ()
console.log("Hello Baby!");
class AttributionalNode extends Node
constructor ()
super();
console.log("AttributionalNode instantiated!");
let attrNode = new AttributionalNode();
attrNode.callMeBaby();
let node = new Node();
【讨论】:
【参考方案4】:虽然问题有一个javascript标签,但因为现在很多项目都在JS之上使用typescript,值得注意的是TS有support for abstract classes and methods out of盒子
abstract class Animal
abstract makeSound(): void;
move(): void
console.log("roaming the earth...");
【讨论】:
【参考方案5】:根据这些cmets,我写了这篇
class AbstractClass
constructor()
if(new.target === AbstractClass || this.__proto__.__proto__.constructor === AbstractClass)
throw new TypeError("Cannot construct "+ this.constructor.name + " class instances directly");
let exceptions = ;
let currProto = this;
while(currProto.constructor !== AbstractClass )
for(let method of (currProto.constructor.abstractMethods || []))
if("function" !== typeof(this[method]))
exceptions[method] = currProto.constructor.name;
currProto = currProto.__proto__;
if(0 !== Object.keys(exceptions).length)
let exceptionsArray = [];
for(let method in exceptions)
exceptionsArray.push( exceptions[method] + "." + method);
exceptionsArray.sort();
throw new TypeError("Must override the following methods: " + exceptionsArray.join(", "));
用法:
class MyAbstractClass1 extends AbstractClass
static abstractMethods = [
"myMethod1", // (x:string, y:string): string
"myMethod2" // (y:string, z:string): string
]
class MyAbstractClass2 extends MyAbstractClass1
static abstractMethods = [
"myMethod3", // (x:string, y:string): string
"myMethod4" // (y:string, z:string): string
]
class MyClass extends MyAbstractClass2
myMethod1(x, y)return "apple"
new MyClass()
//Error
【讨论】:
以上是关于如何在 JavaScript 中创建无法实例化的抽象基类的主要内容,如果未能解决你的问题,请参考以下文章
无法关闭在 Interface Builder 中创建的 NSView 实例的剪辑