Подтвердить что ты не робот

Как создать абстрактный базовый класс в JavaScript, который не может быть создан

У меня есть класс

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();

Итак, он выбрасывает исключение?

4b9b3361

Ответ 1

Это будет работать:

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();

Ответ 2

В механизмах JavaScript, поддерживающих синтаксис класса ECMAScript 2015 (иначе ES6), это можно выполнить с помощью мета-свойства 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 см. раздел 4.2 этого документа.

Ответ 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();