5

プロトタイプ関数を備えたJSのクラスがあるとします...

function Foo() {
    this.stuff = 7;
    this.otherStuff = 5;
}

Foo.prototype.doSomething = function() { };

Foo.prototype.doSomethingElse = function() { };

ここで、このクラスをサブクラス化して「拡張」したいとします。Javaでは、これは次のようになります...

public class Bar extends Foo {}

今、私はJSにはクラスの概念が実際には存在しないことを知っています.別のプロトタイプですよね?

バニラ JS では、そのようなコードはどのように見えるでしょうか?

4

5 に答える 5

5

方法の1つは以下のようなものです、

function Foo() {
    this.stuff = 7;
    this.otherStuff = 5;
}
Foo.prototype.doSomething = function() { alert("some"); };

Foo.prototype.doSomethingElse = function() { };

function Bar() {
   Foo.call(this); // this line
}
Bar.prototype = Object.create(Foo.prototype);

var b = new Bar();
b.doSomething(); 
于 2013-07-17T05:16:57.720 に答える
2

mohkhan が提供したソリューションは時代遅れです。継承を行う新しい方法は次のとおりです。

function Bar() {
    Foo.call(this, /* additional arguments if required */);
}

Bar.prototype = Object.create(Foo.prototype);
Bar.prototype.constructor = Bar;              // don't forget to do this

コードをより古典的に見せたい場合は、augmentメソッドを見てください。拡張を使用すると、上記のコードを次のように記述できます。

var Bar = Foo.augment(function (base) {
    this.constructor = function () {
        base.constructor.call(this, /* additional arguments if required */);
    };
});

メソッド自体はわずか 7 行のaugmentコードです。

Function.prototype.augment = function (body) {
    var base = this.prototype;
    var prototype = Object.create(base);
    body.apply(prototype, Array.prototype.slice.call(arguments, 1).concat(base));
    if (!Object.hasOwnProperty.call(prototype, "constructor")) return prototype;
    var constructor = prototype.constructor;
    constructor.prototype = prototype;
    return constructor;
};

真剣に、新しい方法を使用してください。それは良いです。理由は次のとおりです: Javascript の継承: プロトタイプの設定時に Object.create を呼び出す

于 2013-07-17T06:38:05.893 に答える
2

受け入れられた答えは間違いなくうまくいくでしょう。そして、この「短い」説明はとりとめのないものになりましたが、役に立てば幸いです.

受け入れられた答えで注意しなければならないことが1つあります。基本的に「継承」するときBar.prototype = new Foo()は、コンストラクターを呼び出しています。したがって、別の「クラス」の起動パッドとして使用されることを想定していないコードがコンストラクターにある場合、奇妙な結果が発生します。たとえば、次のようにします。

var Person = function (firstName, lastName) {
    ....
};

var Student = function (firstName, lastName, grade) {
    ....
};

Studentの拡張だとしましょうPerson。でプロトタイプをどのように構築しStudentますか? たぶん好きじゃないStudent.prototype = new Person("John", "Doe");

もう少し複雑ですが、別の関数内にラップできる別の処理方法は次のとおりです。

var extend = function (child, parent) {
    var f = function () {};
    f.prototype = parent.prototype;
    child.prototype = new f();
    child.prototype.constructor = parent;
}

var Person = function (firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
}
Person.prototype.getName = function () {
    return this.firstName + " " + this.lastName;
}
Person.prototype.setAge = function (age) {
    this.age = age;
}


var Student = function (firstName, lastName, grade) {
    Person.call(this, firstName, lastName);
    this.grade = grade;
};

extend(Student, Person); //<< do this before adding stuff to the prototype

Student.prototype.getName = function () {
    var name = Person.prototype.getName.apply(this);
    return name + ", Grade " + this.grade;
}
Student.prototype.tooOldToBeAStudent = function () {
    if(this.age > 18) { return true; }
}

var p = new Person("Joe", "DiMaggio");
var s = new Student("Jack", "Sparrow", 12);
console.log(p.getName(), s.getName());
//consoles "Joe DiMaggio" "Jack Sparrow, Grade 12"
console.log(s instanceof Person); 
//true - even with the weird looking inheritance, Student is still an instance of Person.
s.setAge(30);
console.log(s.age);
//30, just like what you'd expect with a Person object.
console.log(s.tooOldToBeAStudent);
//true - as mentioned previously, 'age' is set via its inherited method.

これにより、Person 機能だけでなく、その上に構築することができます。継承で実際に行うことのようなものです。

それはどのように機能しますか?素晴らしい質問です。まず、オブジェクトは[基本的に]参照によって割り当てられます。プロトタイプはオブジェクトです。そのため、extend関数では、 のサロゲートとして機能する空の関数を作成しますchild。これにより、 のプロトタイプがそれ自体にコピーparentされ、それ自体の新しいインスタンスが のプロトタイプになりchildます。このようにparentのコンストラクターは呼び出されませんが、親のプロトタイプは引き続き使用されます。instanceofそれでも機能することを確認するために、 は -child.prototype.constructorに設定されparent、子がサロゲートからではなく親から来たことを効果的に通知する JavaScript に設定されます。

また、メソッドをオーバーライドするときは、継承元の「クラス」のプロトタイプ メソッドを使用できます。applyこれcallによりthis、現在のオブジェクトのスコープでメソッドを実行し、好きなように感じる任意の引数を渡すことができますが、それらは受け入れられます。あなたが選ぶ機能。たとえば、生徒の現在のインスタンスのコンテキストでPerson.prototype.getName.apply(this);Person を実行します。getNamesetAge をオーバーライドして、年齢を単純に console.logout したいとしましょう。

Student.prototype.setAge = function () {
    Person.prototype.setAge.apply(this, arguments);
    console.log(this.age);
}

ここで起こっているPersonのは、setAgeに渡された引数を使用して が呼び出されていることStudentですsetAge。したがって、基本的には、元のメソッドの引数の詳細を知らなくても、ものを通過させることができます。

于 2013-07-17T05:55:40.510 に答える
2

このようなもの...

function Bar(){
    // your code
}

Bar.prototype = new Foo(); // Bar extends Foo
于 2013-07-17T05:14:05.543 に答える
-3

javascript でクラスを拡張するパターンは java とは異なります

var Person = Class.extend({
  init: function(isDancing){
    this.dancing = isDancing;
  },
  dance: function(){
    return this.dancing;
  }
});

var Ninja = Person.extend({
  init: function(){
    this._super( false );
  },
  dance: function(){
    // Call the inherited version of dance()
    return this._super();
  },
  swingSword: function(){
    return true;
  }
});

var p = new Person(true);
p.dance(); // => true

var n = new Ninja();
n.dance(); // => false
n.swingSword(); // => true

// Should all be true
p instanceof Person && p instanceof Class &&
n instanceof Ninja && n instanceof Person && n instanceof Class
于 2013-07-17T05:11:23.183 に答える