1. ホーム
  2. javascript

[解決済み] Javascriptの継承:スーパーコンストラクタを呼び出すか、プロトタイプチェーンを使用するか?

2023-06-24 14:53:07

質問

ごく最近、MDC における JavaScript 呼び出しの使用について読みました。

https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/call

以下に示す例の一つのリンク、私はまだ理解していない。

なぜここで継承を使うのか

Prod_dept.prototype = new Product();

は必要なのでしょうか?の中にスーパーコンストラクタへの呼び出しがあるからです。

Prod_dept()

とにかく、このように

Product.call

は、単に一般的な動作から外れているだけなのでしょうか?スーパーコンストラクタの呼び出しやプロトタイプチェーンの使用はいつが良いのでしょうか?

function Product(name, value){
  this.name = name;
  if(value >= 1000)
    this.value = 999;
  else
    this.value = value;
}

function Prod_dept(name, value, dept){
  this.dept = dept;
  Product.call(this, name, value);
}

Prod_dept.prototype = new Product();

// since 5 is less than 1000, value is set
cheese = new Prod_dept("feta", 5, "food");

// since 5000 is above 1000, value will be 999
car = new Prod_dept("honda", 5000, "auto");

わかりやすい説明ありがとうございます。

どのように解決するのですか?

本当の質問の答えは、両方を行う必要があるということです。

  • prototype を親のインスタンスに設定すると、prototype チェーン (継承) が初期化され、これは一度だけ行われます (prototype オブジェクトが共有されるため)。
  • 親のコンストラクタを呼び出すと、オブジェクト自体が初期化されます。これはインスタンス化のたびに行われます(コンストラクタのたびに異なるパラメータを渡すことができます)。

したがって、継承を設定する際には、親のコンストラクタを呼び出してはいけません。他のオブジェクトを継承するオブジェクトをインスタンス化するときだけです。

Chris Morganの回答はほぼ完璧ですが、細かい点(コンストラクタのプロパティ)が抜けています。継承を設定するための方法を提案させてください。

function extend(base, sub) {
  // Avoid instantiating the base class just to setup inheritance
  // Also, do a recursive merge of two prototypes, so we don't overwrite 
  // the existing prototype, but still maintain the inheritance chain
  // Thanks to @ccnokes
  var origProto = sub.prototype;
  sub.prototype = Object.create(base.prototype);
  for (var key in origProto)  {
     sub.prototype[key] = origProto[key];
  }
  // The constructor property was set wrong, let's fix it
  Object.defineProperty(sub.prototype, 'constructor', { 
    enumerable: false, 
    value: sub 
  });
}

// Let's try this
function Animal(name) {
  this.name = name;
}

Animal.prototype = {
  sayMyName: function() {
    console.log(this.getWordsToSay() + " " + this.name);
  },
  getWordsToSay: function() {
    // Abstract
  }
}

function Dog(name) {
  // Call the parent's constructor
  Animal.call(this, name);
}

Dog.prototype = {
    getWordsToSay: function(){
      return "Ruff Ruff";
    }
}    

// Setup the prototype chain the right way
extend(Animal, Dog);

// Here is where the Dog (and Animal) constructors are called
var dog = new Dog("Lassie");
dog.sayMyName(); // Outputs Ruff Ruff Lassie
console.log(dog instanceof Animal); // true
console.log(dog.constructor); // Dog

クラスを作成する際のさらなる構文上の工夫については、私のブログ記事を参照してください。 http://js-bits.blogspot.com/2010/08/javascript-inheritance-done-right.html

Ext-JSからコピーしたテクニックと http://www.uselesspickles.com/class_library/ からのコメントと https://stackoverflow.com/users/1397311/ccnokes