3

私は C++ に堪能なので、OOP のバックグラウンドは十分にありますが、JavaScript は初めてで、JavaScript でポリモーフィズムを適切に実装する方法を理解しようとしています。このトピックに関連する多くのチュートリアルと StackOverflow の質問を読みましたが、基本クラスから正しく継承し、新しいメンバーを子クラスに追加する方法について詳細に説明したものはありません。

function Obj1() {}
function Obj2() {}
function Obj3() {}

Obj2.prototype === Obj3.prototype;  // false

好奇心 #1:Obj2Obj3(さらに言え ば ) の両方が をObj1継承しObjectている場合、それらのプロトタイプが同一でないのはなぜですか? Obj2Obj3それぞれが の独自のコピーを受け取りましたかObject?

Obj2.prototype = Object;
Obj2.prototype = Object;
Obj2.prototype === Obj3.prototype;  // true
Obj2.prototype = Obj1;
Obj3.prototype = Obj1;
Obj2.prototype === Obj3.prototype;  // true

好奇心 2: どちらの場合も、Obj2現在Obj3は同じプロトタイプを共有しています。変化したこと?

Obj2.prototype.pi = function() {  return 3.14159;  }
Obj2.prototype.pi();  // 3.14159
Obj3.prototype.pi();  // 3.14159
Obj1.pi();  // 3.14159

本当の問題: のプロトタイプを変更すると、 のプロトタイプと関数自体Obj2も変更されます。この C++ プログラマーにとって、これはすべて非常にショッキングなことですが、上記の構文からまさに私が予想したとおりでした。結局のところ、 と のプロトタイプは両方とも と同一視されているため、1 つを変更すると、他の 2 つも同じように変更されます。それにもかかわらず、との両方の基本クラスとして使用し、またはによってまったく共有されない新しい関数挿入したいと考えています。それ、どうやったら出来るの?Obj3Obj1Obj2Obj3Obj1Obj1Obj2Obj3 Obj2Obj1Obj3

これらのオブジェクトがインスタンス化されると、さらに興味深いことが起こります。

var x = new Obj2();
x.pi();  // 3.14159
var y = new Obj3();
y.pi();  // 3.14159
var z = new Obj1();
z.pi();  // Error: pi() not defined on z.

Obj2Obj3両方とも関数を持っています。これは、関数を含む基本クラスpi()を共有していることを意味します。この基本クラスは他ではありません— しかし、反対の証拠にもかかわらず、のインスタンスには が含まれていません!pi()Obj1Obj1pi()

4

3 に答える 3

2

あなたの最初の証明では:

function a () {};
function b () {};

a.prototype === b.prototype; // false

prototypeそうではないという事実にぶつかっていますObject-それは基本クラスではありません。これは、 のメソッドとプロパティを使用して、プロトタイプとして拡張されたオブジェクトですObject
また、同じオブジェクトへの 2 つのポインターをテストしない限り、すべてのテストで{} === {};false, alwaysが返されます。

var a = {},
    b = a;

a === b; // true

Object3 つの関数すべてを同じオブジェクト (最初はそれ自体、次にObj1プロトタイプ オブジェクト)を指すように設定したため、継承の難破船はその後、この概念の欠落を直接指しています。
Aprototypeliveです。プロトタイプへの変更は、オブジェクトの構築後に、そのオブジェクトへのポインターを含むオブジェクトに反映されます。

と、まったく同じオブジェクトへのポインターを指定Obj1しました。 したがって、すべてが共有するプロトタイプ オブジェクトへの変更は、構築されたすべてのオブジェクトに反映されます。プロパティにアクセスしようとすると、継承の解決がリアルタイムで行われるためです (静的で事前にコンパイルされた GOTO に存在するのではなく)。州)。Obj2Obj3

サブクラス化する機能が必要な場合は、次のようにすることができます。

var A = function () {};
A.prototype.foo = function () {};
var a = new A();

var B = function () {};
B.prototype = a; // or new A(); -- an object which can live-lookup the prototype of A
// problem is, `constructor` on the prototype will now point to `A`, so...
B.prototype.constructor = B; // now b instanceof B should work in tests
B.bar = function () {};


var b = new B();
b.foo(); // A.prototype.foo
b.bar(); // B.prototype.bar

しかし、実際には、これを拡張しすぎると気が狂ってしまいます。
JS で従うべきより健全な道は、コンポーネントベースのオブジェクト構築と依存性注入です。

于 2012-10-07T16:12:41.853 に答える
1

このprototypeプロパティはオブジェクトも返します。これはオブジェクトのインスタンスですが、同じインスタンスではないため、それらは同じオブジェクトではなく、等しいかどうかを比較すると当然 false が返されます。

より詳細には、Obj1、Obj2、Obj3 はすべて関数とオブジェクトであり、それらのプロトタイプもオブジェクトです。C++ の用語では、prototypeプロパティをクラス定義や基本クラスではなく、別のオブジェクトへのポインターと考えてください。

Obj2 の場合、次のように別のメソッドを宣言します。

function Obj2() {
    this.prototype = new Obj1();
    this.myOwnMethod = function (x) { ... }
}

私は自分の言葉で Javascript のオブジェクト指向の適切な説明を書こうとしていましたが、それには時間がかかりすぎると思います :) 代わりに、私が書いた半分一貫したテキストを削除し、理解するのに役立つ 2 つの指針を与えることにしました。より深く、うまくいけば、彼らもあなたを助けるでしょう:

于 2012-10-07T15:50:49.800 に答える
-3

Use ember or backbone or some other framework to extract this for you. There's a lot of monkeying required to get inheritance to work like you expect.

于 2012-10-07T15:54:18.580 に答える