web-dev-qa-db-ja.com

インスタンス化できない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();

だから、例外をスローしますか?

33

これはうまくいくでしょう:

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を参照することはできません。

また、JSクラスを適切に拡張する方法に関する優れた記事については、 ここを参照 を参照してください。

13
levi

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の詳細については、 このドキュメント のセクション4.2を参照してください。

46

@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();
6
Ciro Costa

これらのコメントに基づいて、私はこれを書きました

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
0
somla