2011-01-24 17 views
2

このコードで何が問題になっていますか?誰かがJavaScript Object Inheritanceを教えてくれますか?私は馬鹿のように感じ始めている!!事前にJavaScript Object継承 - 何が間違っていますか?

おかげで、 サム

function Human(name, sex) { 
    this.name = name; 
    this.sex = sex; 
}; 

function Man(name) { 
    Man.prototype = new Human(name, "Male"); 
}; 

var m = new Man("Sam Striano"); 
alert(m.name); //<-- = Undefined 

答えて

1

JavaScriptで古典の継承を模倣するには、2つのステップは通常あります:

  1. は、あなたのサブクラスのコンストラクタは

  2. あなたのサブクラスのプロトタイプは、親プロトタイプ

に連鎖する必要がある親のコンストラクタを呼び出す必要があります

最初のステップは通常のように見えます

function Subclass(blah) { 
    ParentClass.apply(this, arguments); 
} 

第2ステップはトリッキーです。あなたのスクリプトが(Node.jsの環境でのように)実行される場所を正確に知っている限り__proto__プロパティを実装JS環境では、あなたが

Subclass.prototype = { 
    __proto__ : ParentClass.prototype, 
    subclassMethod1: function() { /* ... */ } 
} 

を行うことができ、あなたのスクリプトで使用されて__proto__に頼ることはできませんので、一般的なアプローチはCrockford's object() methodを使用する必要があります:それの要点です

if (typeof Object.create !== 'function') { 
    Object.create = function (o) { 
     function F() {} 
     F.prototype = o; 
     return new F(); 
    }; 
} 
Subclass.prototype = Object.create(ParentClass.prototype); 
Subclass.prototype.subclassMethod1 = function() { /* ... */ } 

を。 ES5のランタイムには既にObject.create()が組み込まれているかもしれません。

親クラスのオーバーライドメソッドを簡単に呼び出す機能など、古典的な継承の錯覚を完成させるために残されたことがあります。今のところ、SubclassメソッドにParentClass.prototype.overridenMethod.call(this, arg1, arg2)のようなものが必要です。 いくつかのOOライブラリは、サブクラスインスタンスごとに追加のcruftを定義することに役立ちますので、this.superclass.overridenMethod(arg1, arg2)のようなものを使用できます。

その嫌なものの実装は読者への課題として残されている。私はあなたが後にしているものを考える)

+0

メソッドは、ベースとサブの両方で定義する必要がありますか? JavaScriptを使って基本的な古典的継承の完全な例を教えてください。 – Sam

2

あなたはこの代わりにしたい:

function Man(name) { 
    Human.call(this, name, "Male"); 
} 

そのコードは、あなただけ呼び出すしようとしているように思え

何親のコンストラクタHumanはプロトタイプの継承ではありません。上のコードはHumanのコンストラクタをとり、this - 新しいManオブジェクトに適用します。

あなたのコードが行Man.prototype = new Human(name, "Male")Manのプロトタイプ新しい男がを作成されるたびに変化している

何。それだけでなく、プロトタイプオブジェクトの再割り当てが完了しているので、の後に割り当てられたオブジェクトにのみ適用されます。つまり、最初のオブジェクトではありません。したがって、m.nameは未定義です。

適切原型継承

注自動的Human.prototypeに割り当てられたすべてのメソッドを継承するためにMan原因はなりません、上記の私のコードのように、親のコンストラクタを呼び出すこと。これを行う最善の方法は、Human.prototypeMan.prototypeにクローンし、コンストラクタの外にクローンすることです。このように:

function Man(name) { 
    Human.call(this, name, "Male"); 
} 

function inherit(parent, child) { 
    if (Object.create) child.prototype = Object.create(parent.prototype); 
    else { 
     for (var key in parent.prototype) { 
      if (!parent.prototype.hasOwnProperty(key)) continue; 
      child.prototype[key] = parent.prototype[key]; 
     } 
    } 
} 

inherit(Human, Man); 

これはかなり冗長に見えるかもしれませんが、代替はこれを実行することがあります

を動作しますが、我々はに強制しているので、望ましくない副作用を引き起こします
Man.prototype = new Human('no name', 'Male'); 

prototypeにダッド名を割り当てて、Humanのコンストラクタにプロトタイプを割り当てるだけの余分な時間を呼ぶようにします。このパスを終了し、後でthisにプロパティを割り当てる以外にも、Humanコンストラクタを変更すると警告されます。

+0

プロトタイプと "__prototype__"の違いは何ですか? – Sam

+0

文字列、配列、数値、ブール値などと似ていますか?だから、この例題は "Prototypical Inheritance"ではありませんか? – Sam

+0

@Sam、私の間違いは、あなたが '__proto__'を意味すると思います。それはそれを構築した関数のプロトタイプに新しいオブジェクトを結びつけることです。しかし、これを使用するべきではありません。詳しくはhttps://developer.mozillaを参照してください。org/ja/JavaScript/Reference/Global_Objects/Object/proto –

1

Humanから継承するプロパティでManクラスを持つことです。正しい軌道に乗っていますが、新しいHumanインスタンスをプロトタイプオブジェクトManとして1回適用する必要があります。

function Human(name, sex) { 
    this.name = "some default"; 
    this.sex = sex; 
}; 

function Man(name) { 
    if(name !== undefined) 
     this.name = name; 
}; 
Man.prototype = new Human(name, "Male"); 
Man.prototype.constructor = Man; 

var m = new Man("Sam Striano"); 

alert(m.name); // alerts "Sam Striano" 
alert(m.sex); // alerts "Male" 
+0

今私はちょうどこれと "Box9"から上記の答えの間に混乱している??? – Sam

+0

@サム:あなたは混乱している部分はありますか? – user113716

+0

@Sam:[これを実装する方法の例はこちら](http://jsfiddle.net/Xyg3s/)。いくつかのアイテムが 'Human'にプロトタイプ化されています。これは' Human'すべてに適用されます。そして、それぞれの 'Human'インスタンスは、' Man'と 'Woman'の親クラスとしての役割を果たす' sex'のプロパティを持つことができます。それぞれの 'Man'はそれ自身の' name'プロパティを持つことができます。 'Human'は' name'に警告する 'speak'関数を持っているので、' Man'はそれぞれ 'name'を話すことができます。 – user113716

1

私の知る限りでは、あなたはprototypeconstructorですべてのものを処理しなければならないとinerithanceは、この方法で管理することができます


// Define superclass  
function Human(name, sex) { 
    this.name = name; 
    this.sex = sex; 
}         

// Define superclass methods  
Human.prototype.method1 = function() { 
    alert('This is the call to ORIGINAL method1() with name: ' + this.name + ' and sex: ' + this.sex); 
} 

// Define subclass  
function Man(name, age) {           
    this.constructor.apply(this, [ name, 'Man' ]); 
    this.age = age; 
}  

// Define subclass inerithance 
Man.prototype = new Human(); 

// Define subclass methods 
Man.prototype.method1 = function() { 
    alert('This is the call to OVERWRITE method1() with name: ' + this.name + ' and sex: ' + this.sex + ' and age: ' + this.age); 
    this.constructor.prototype.method1.apply(this); 
} 

var m = new Man('Sam Satriano', 30); 
m.method1(); 
// Should alert: 
// This is the call to OVERWRITE method1() with name: Sam Satriano and sex: Man and age: 30 
// This is the call to ORIGINAL method1() with name: Sam Satriano and sex: Man 

は、この情報がお役に立てば幸いです。チャオ!

+0

Btwには、「スーパー」の動作をシミュレートする興味深いjQueryプラグイン(低プロhttps://github.com/danwrong/low-pro-for-jquery/など)がいくつかあります。 – lomanf

+0

Manコンストラクタでは、同じコンストラクタではなく、親のコンストラクタを呼び出す必要があります。あなたの例は、継承を設定するときに、 'Man.prototype = new Human()'の後にプロトタイプにコンストラクタ・プロパティを修正しなかったためにのみ機能します –

1

継承の戦いに入るがなければ、あなたの問題は、次のようにコードを変更することで解決することができます。

function Human(name, sex) { 
    this.name = name; 
    this.sex = sex; 
}; 

function Man(name) { 
    // This is how you call the parent's constructor 
    Human.call(this, name, "Male"); 
}; 

// The call to setup the prototype only needs to happen once 
// Not in every instantiation of the object 
Man.prototype = new Human(); 
// Have to fix the constructor, right now it's set to Human 
Man.prototype.constructor = Man; 

var m = new Man("Sam Striano"); 
>> m.name // outputs "Sam Striano"; 
>> m instanceof Human // outputs true 

は、これはまだ継承するための理想的な方法ではありません。私は良いJS継承を作るものを説明するものを投稿しました。 http://js-bits.blogspot.com/2010/08/javascript-inheritance-done-right.html

関連する問題