How to create Abstract base class in JavaScript that can't be Instantiated
Solution 1
This would work:
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();
Note: you cannot refer to this.prototype
inside the constructor, as the prototype is only a property of the constructor function, not of the instances.
Also, see here for a good article on how to properly extend JS classes.
Solution 2
In JavaScript engines that support ECMAScript 2015 (aka ES6) class syntax, this can be accomplished using the new.target
meta-property:
function Node() {
if (new.target === Node) throw TypeError("new of abstract class Node");
}
or using class syntax:
class Node {
constructor () {
if (new.target === Node) throw TypeError("new of abstract class Node");
}
}
in either case, just define AttributionalNode
as:
class AttributionalNode extends Node {
constructor () {
super();
}
setAttr(attr) {
this.atText = attr;
}
}
new Node(); // will throw TypeError
new AttributionalNode(); // works fine
For a more detailed explanation of new.target
see section 4.2 of this document.
Solution 3
Adapting @levi's answer, you can go with a similar solution for using with ES6 today (as new.target
isn't established yet):
You can see it running on Babel's 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();
Solution 4
Although the question has a javascript tag, because nowadays a lot of projects are using typescript on top of JS, it's worth noting that TS has support for abstract classes and methods out of the box
abstract class Animal {
abstract makeSound(): void;
move(): void {
console.log("roaming the earth...");
}
}
![Alexandr Sargsyan](https://i.stack.imgur.com/sWom7.jpg?s=256&g=1)
Alexandr Sargsyan
Updated on June 03, 2022Comments
-
Alexandr Sargsyan about 2 years
I have a class
function Node() { //implementation }
and another class
function AttributionalNode() { this.prototype.setAttr = function (attr) { this.atText = attr; }; } AttributionalNode.prototype = new Node(); AttributionalNode.prototype.constructor = AttributionalNode;
How to make class Node() so it can't be instantiated? e.g when I try
var node = new Node();
So it throws an Exception?
-
Admin about 9 yearsCan you provide a reference for
new.target
? -
Alexandr Sargsyan about 9 yearsIt throughs error when some class try to inherit from Node()
-
levi about 9 years@AlexandrSargsyan It does not. I updated the example to demonstrate this.
-
Ciro Costa about 9 yearsIf you wish to know whether it supports or not: kangax.github.io/compat-table/es6/#new.target . At this moment, no support, as stated.
-
zypA13510 almost 6 years
-
Donald Duck over 4 yearsIs there any difference between
new.target
andthis.constructor
?