82

ごく最近、MDCでのJavaScript呼び出しの使用法について読みました

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

以下に示す例の1つのリンクですが、まだわかりません。

なぜ彼らはこのようにここで継承を使用しているのですか

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

物事を明確にしてくれてありがとう

4

3 に答える 3

110

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

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

したがって、継承を設定するときに親のコンストラクターを呼び出さないでください。別のオブジェクトから継承するオブジェクトをインスタンス化する場合のみ。

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からのコメント

于 2010-12-08T15:52:57.083 に答える
30

これを行う理想的な方法は、コンストラクターを呼び出すため、実行しないことです。したがって、理想的な方法は、コンストラクターを除いて、次のようにクローンを作成することです。Prod_dept.prototype = new Product();Product

function Product(...) {
    ...
}
var tmp = function(){};
tmp.prototype = Product.prototype;

function Prod_dept(...) {
    Product.call(this, ...);
}
Prod_dept.prototype = new tmp();
Prod_dept.prototype.constructor = Prod_dept;

次に、構築時にスーパーコンストラクターが呼び出されます。これは、パラメーターを渡すこともできるためです。

Google Closure Libraryのようなものを見ると、それがその方法であることがわかります。

于 2010-11-11T09:32:59.940 に答える
6

JavaScriptでオブジェクト指向プログラミングを行ったことがある場合は、次のようにクラスを作成できることがわかります。

Person = function(id, name, age){
    this.id = id;
    this.name = name;
    this.age = age;
    alert('A new person has been accepted');
}

これまでのところ、クラスの担当者には2つのプロパティしかなく、いくつかのメソッドを提供します。これを行うためのクリーンな方法は、その「プロトタイプ」オブジェクトを使用することです。JavaScript 1.1から、プロトタイプオブジェクトがJavaScriptに導入されました。これは、オブジェクトのすべてのインスタンスにカスタムプロパティとメソッドを追加するプロセスを簡素化する組み込みオブジェクトです。次のように、「prototype」オブジェクトを使用して、クラスに2つのメソッドを追加しましょう。

Person.prototype = {
    /** wake person up */
    wake_up: function() {
        alert('I am awake');
    },

    /** retrieve person's age */
    get_age: function() {
        return this.age;
    }
}

これで、クラスPersonを定義しました。Personからいくつかのプロパティを継承するManagerという別のクラスを定義したい場合はどうでしょうか。Managerクラスを定義するときに、このすべてのプロパティを再定義する意味はありません。クラスPersonから継承するように設定するだけです。JavaScriptには継承が組み込まれていませんが、次のように継承を実装する手法を使用できます。

Inheritance_Manager = {};//継承マネージャークラスを作成します(名前は任意です)

次に、継承クラスに、baseClass引数とsubClassas引数を受け取るextendというメソッドを指定しましょう。extendメソッド内に、継承関数inheritance(){}という内部クラスを作成します。この内部クラスを使用する理由は、baseClassプロトタイプとsubClassプロトタイプの間の混乱を避けるためです。次に、次のコードのように、継承クラスのプロトタイプがbaseClassプロトタイプを指すようにします。inheritance.prototype=baseClass。プロトタイプ; 次に、継承プロトタイプを次のようにsubClassプロトタイプにコピーします。subClass.prototype= new inheritance(); 次に、subClassのコンストラクターを次のように指定します。subClass.prototype.constructor= subClass; サブクラスのプロトタイピングが終了したら、次の2行のコードを指定して、いくつかの基本クラスのポインターを設定できます。

subClass.baseConstructor = baseClass;
subClass.superClass = baseClass.prototype;

拡張関数の完全なコードは次のとおりです。

Inheritance_Manager.extend = function(subClass, baseClass) {
    function inheritance() { }
    inheritance.prototype = baseClass.prototype;
    subClass.prototype = new inheritance();
    subClass.prototype.constructor = subClass;
    subClass.baseConstructor = baseClass;
    subClass.superClass = baseClass.prototype;
}

継承を実装したので、それを使用してクラスを拡張できます。この場合、次のようにPersonクラスをManagerクラスに拡張します。

Managerクラスを定義します

Manager = function(id, name, age, salary) {
    Person.baseConstructor.call(this, id, name, age);
    this.salary = salary;
    alert('A manager has been registered.');
}

Personから継承させます

Inheritance_Manager.extend(Manager, Person);

お気づきの方もいらっしゃると思いますが、Inheritance_Managerクラスのextendメソッドを呼び出して、この場合はsubClass Managerを渡し、次にbaseClassPersonを渡しました。ここでは順序が非常に重要であることに注意してください。それらを交換すると、継承は意図したとおりに機能しなくなります。また、サブクラスを実際に定義する前に、この継承を指定する必要があることに注意してください。次に、サブクラスを定義しましょう。

以下のようにメソッドを追加できます。Managerクラスは、Personクラスから継承するため、常にPersonクラスで定義されたメソッドとプロパティを持ちます。

Manager.prototype.lead = function(){
   alert('I am a good leader');
}

それをテストするために、2つのオブジェクトを作成しましょう。1つはクラスPersonからのもので、もう1つは継承されたクラスManagerからのものです。

var p = new Person(1, 'Joe Tester', 26);
var pm = new Manager(1, 'Joe Tester', 26, '20.000');

http://www.cyberminds.co.uk/blog/articles/how-to-implement-javascript-inheritance.aspxで、完全なコードとその他のコメントを自由に入手して ください。

于 2011-12-21T21:20:32.217 に答える