如何在 JavaScript 中创建无法实例化的抽象基础 class
How to create Abstract base class in JavaScript that can't be Instantiated
我有一个class
function Node() {
//implementation
}
还有一个class
function AttributionalNode() {
this.prototype.setAttr = function (attr) {
this.atText = attr;
};
}
AttributionalNode.prototype = new Node();
AttributionalNode.prototype.constructor = AttributionalNode;
如何使 class Node() 无法实例化?
例如,当我尝试
var node = new Node();
所以它抛出异常?
这可行:
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 的好文章 类。
在支持 ECMAScript 2015(又名 ES6)class 语法的 JavaScript 引擎中,这可以使用 new.target
meta-属性:
function Node() {
if (new.target === Node) throw TypeError("new of abstract class Node");
}
或使用 class 语法:
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 节。
采用@levi 的回答,您可以使用类似的解决方案来使用今天的 ES6(因为 new.target
尚未建立):
你可以在 Babel 的回复上看到它 运行: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();
根据这些评论,我写了这个
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标签,因为现在很多项目都在JS之上使用typescript ,值得注意的是 TS 已经 support for abstract classes and methods 开箱即用
abstract class Animal {
abstract makeSound(): void;
move(): void {
console.log("roaming the earth...");
}
}
我有一个class
function Node() {
//implementation
}
还有一个class
function AttributionalNode() {
this.prototype.setAttr = function (attr) {
this.atText = attr;
};
}
AttributionalNode.prototype = new Node();
AttributionalNode.prototype.constructor = AttributionalNode;
如何使 class Node() 无法实例化? 例如,当我尝试
var node = new Node();
所以它抛出异常?
这可行:
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 的好文章 类。
在支持 ECMAScript 2015(又名 ES6)class 语法的 JavaScript 引擎中,这可以使用 new.target
meta-属性:
function Node() {
if (new.target === Node) throw TypeError("new of abstract class Node");
}
或使用 class 语法:
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 节。
采用@levi 的回答,您可以使用类似的解决方案来使用今天的 ES6(因为 new.target
尚未建立):
你可以在 Babel 的回复上看到它 运行: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();
根据这些评论,我写了这个
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标签,因为现在很多项目都在JS之上使用typescript ,值得注意的是 TS 已经 support for abstract classes and methods 开箱即用
abstract class Animal {
abstract makeSound(): void;
move(): void {
console.log("roaming the earth...");
}
}