2015-05-31 15 views
25

Mam klasyJak stworzyć abstrakcyjną klasą bazową w JavaScript, który nie może być instancja

function Node() { 
    //implementation 
} 

i inna klasa

function AttributionalNode() { 
    this.prototype.setAttr = function (attr) { 
     this.atText = attr; 
    }; 
} 

AttributionalNode.prototype = new Node(); 
AttributionalNode.prototype.constructor = AttributionalNode; 

Jak class node(), więc nie może być utworzone? przykład gdy próbuję

var node = new Node(); 

Więc zgłasza wyjątek?

+0

Umieścić 'throw new Exception()' w konstruktorze, może? Nie wiem, czy to jest ważne w JavaScript. –

+0

Generalnie nie jest dobrym pomysłem ustawianie właściwości prototypu w funkcji konstruktora. – Pointy

Odpowiedz

10

to będzie działać:

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

Uwaga: nie można odwołać się do this.prototype wewnątrz konstruktora, jako prototyp jest tylko właściwością funkcji konstruktora, a nie instancje.

Ponadto, see here za dobry artykuł o tym, jak prawidłowo rozszerzyć klasy JS.

+0

Występuje błąd, gdy niektóre klasy próbują dziedziczyć z węzła() –

+2

@AlexandrSargsyan Nie ma. Zaktualizowałem przykład, aby to pokazać. – levi

41

W silnikach JavaScript obsługujących ECMAScript 2015 (aka ES6) składnia klasy, można to osiągnąć za pomocą new.target meta-właściwość:

function Node() { 
    if (new.target === Node) throw TypeError("new of abstract class Node"); 
} 

lub przy użyciu klasy składni:

class Node { 
    constructor() { 
     if (new.target === Node) throw TypeError("new of abstract class Node"); 
    } 
} 

w jednej obudowa, po prostu zdefiniuj AttributionalNode jako:

class AttributionalNode extends Node { 
    constructor() { 
     super(); 
    } 
    setAttr(attr) { 
     this.atText = attr; 
    } 
} 

new Node();    // will throw TypeError 
new AttributionalNode(); // works fine 

Bardziej szczegółowe objaśnienie new.target znajduje się w punkcie 4.2 pod numerem this document.

+1

Czy możesz podać referencję dla 'new.target'? –

+0

new.target nie działa! –

+1

Jeśli chcesz wiedzieć, czy to obsługuje, czy nie: https://kangax.github.io/compat-table/es6/#new.target. W tej chwili brak wsparcia, jak stwierdzono. –

5

Adaptacja @ odpowiedź Levi, można iść z podobnego rozwiązania dla korzystania z ES6 dzisiaj (jak new.target nie jest jeszcze ustalone):

Widać to działa na Babla 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(); 
Powiązane problemy