80

私は基本クラスを持っています:

function Monster() {
  this.health = 100;
}

Monster.prototype.growl = function() {
  console.log("Grr!");
}

私が拡張して別のクラスを作成したいのは:

function Monkey extends Monster() {
  this.bananaCount = 5;
}

Monkey.prototype.eatBanana {
  this.bananaCount--;
  this.health++; //Accessing variable from parent class monster
  this.growl();  //Accessing function from parent class monster
}

私はかなりの調査を行いましたが、JavaScriptでこれを行うための複雑な解決策がたくさんあるようです。JSでこれを達成するための最も簡単で信頼できる方法は何でしょうか?

4

10 に答える 10

157

ES6用に以下を更新

2013年3月およびES5

このMDNドキュメントでは、クラスの拡張について詳しく説明しています。

https://developer.mozilla.org/en-US/docs/JavaScript/Introduction_to_Object-Oriented_JavaScript

特に、ここで彼らはそれを処理します:

// define the Person Class
function Person() {}

Person.prototype.walk = function(){
  alert ('I am walking!');
};
Person.prototype.sayHello = function(){
  alert ('hello');
};

// define the Student class
function Student() {
  // Call the parent constructor
  Person.call(this);
}

// inherit Person
Student.prototype = Object.create(Person.prototype);

// correct the constructor pointer because it points to Person
Student.prototype.constructor = Student;

// replace the sayHello method
Student.prototype.sayHello = function(){
  alert('hi, I am a student');
}

// add sayGoodBye method
Student.prototype.sayGoodBye = function(){
  alert('goodBye');
}

var student1 = new Student();
student1.sayHello();
student1.walk();
student1.sayGoodBye();

// check inheritance
alert(student1 instanceof Person); // true 
alert(student1 instanceof Student); // true

Object.create()IE8を含む一部の古いブラウザではサポートされていないことに注意してください。

Object.createブラウザのサポート

これらをサポートする必要がある場合は、リンクされたMDNドキュメントで、ポリフィルまたは次の近似値を使用することをお勧めします。

function createObject(proto) {
    function ctor() { }
    ctor.prototype = proto;
    return new ctor();
}

このようStudent.prototype = createObject(Person.prototype)に使用new Person()することは、プロトタイプを継承するときに親のコンストラクター関数を呼び出さないようにし、継承者のコンストラクターが呼び出されるときにのみ親コンストラクターを呼び出すという点で、使用するよりも望ましい方法です。

2017年5月およびES6

ありがたいことに、JavaScriptの設計者は私たちの助けを求める声を聞いており、この問題に取り組むためのより適切な方法を採用しています。

MDNには、ES6クラスの継承に関する別の優れた例がありますが、ES6で再現された上記とまったく同じクラスのセットを示します。

class Person {
    sayHello() {
        alert('hello');
    }

    walk() {
        alert('I am walking!');
    }
}

class Student extends Person {
    sayGoodBye() {
        alert('goodBye');
    }

    sayHello() {
        alert('hi, I am a student');
    }
}

var student1 = new Student();
student1.sayHello();
student1.walk();
student1.sayGoodBye();

// check inheritance
alert(student1 instanceof Person); // true 
alert(student1 instanceof Student); // true

私たち全員が望むように、清潔で理解しやすい。ES6はかなり一般的ですが、どこでもサポートされているわけではないことに注意してください。

ES6ブラウザのサポート

于 2013-03-04T00:33:56.190 に答える
22

ES6 では、classおよびextendsキーワードを使用できるようになりました。

次に、コードは次のようになります。

基本クラスがあります:

class Monster{
       constructor(){
             this.health = 100;
        }
       growl() {
           console.log("Grr!");
       }

}

拡張して別のクラスを作成する場合:

class Monkey extends Monster {
        constructor(){
            super(); //don't forget "super"
            this.bananaCount = 5;
        }


        eatBanana() {
           this.bananaCount--;
           this.health++; //Accessing variable from parent class monster
           this.growl(); //Accessing function from parent class monster
        }

}
于 2016-08-06T00:46:05.020 に答える
10

これを試して:

Function.prototype.extends = function(parent) {
  this.prototype = Object.create(parent.prototype);
};

Monkey.extends(Monster);
function Monkey() {
  Monster.apply(this, arguments); // call super
}

編集:ここに簡単なデモを掲載しましたhttp://jsbin.com/anekew/1/edit。これextendsはJSで予約語であり、コードをリントするときに警告が表示される場合があることに注意してください。名前を付けるだけでinherits、通常はこれを実行します。

このヘルパーを配置し、オブジェクトpropsを唯一のパラメーターとして使用すると、JSでの継承が少し簡単になります。

Function.prototype.inherits = function(parent) {
  this.prototype = Object.create(parent.prototype);
};

function Monster(props) {
  this.health = props.health || 100;
}

Monster.prototype = {
  growl: function() {
    return 'Grrrrr';
  }
};

Monkey.inherits(Monster);
function Monkey() {
  Monster.apply(this, arguments);
}

var monkey = new Monkey({ health: 200 });

console.log(monkey.health); //=> 200
console.log(monkey.growl()); //=> "Grrrr"
于 2013-03-04T00:35:23.053 に答える
6

プロトタイプのアプローチが気に入らない場合は、実際には適切な OOP の方法で動作しないため、これを試すことができます。

var BaseClass = function() 
{
    this.some_var = "foobar";

    /**
     * @return string
     */
    this.someMethod = function() {
        return this.some_var;
    }
};

var MyClass = new Class({ extends: BaseClass }, function()
{
    /**
     * @param string value
     */
    this.__construct = function(value)
    {
        this.some_var = value;
    }
})

軽量ライブラリの使用 (2k 縮小): https://github.com/haroldiedema/joii

于 2014-01-22T15:55:15.103 に答える
0

従来の拡張では、単にスーパークラスをコンストラクター関数として記述し、このコンストラクターを継承されたクラスに適用できます。

     function AbstractClass() {
      this.superclass_method = function(message) {
          // do something
        };
     }

     function Child() {
         AbstractClass.apply(this);
         // Now Child will have superclass_method()
     }

angularjs の例:

http://plnkr.co/edit/eFixlsgF3nJ1LeWUJKsd?p=preview

app.service('noisyThing', 
  ['notify',function(notify){
    this._constructor = function() {
      this.scream = function(message) {
          message = message + " by " + this.get_mouth();
          notify(message); 
          console.log(message);
        };

      this.get_mouth = function(){
        return 'abstract mouth';
      }
    }
  }])
  .service('cat',
  ['noisyThing', function(noisyThing){
    noisyThing._constructor.apply(this)
    this.meow = function() {
      this.scream('meooooow');
    }
    this.get_mouth = function(){
      return 'fluffy mouth';
    }
  }])
  .service('bird',
  ['noisyThing', function(noisyThing){
    noisyThing._constructor.apply(this)
    this.twit = function() {
      this.scream('fuuuuuuck');
    }
  }])
于 2015-08-25T19:06:17.027 に答える