• ベストアンサー

クラスの継承の仕方

後学のため、JavaScriptについて勉強しています。 JavaScriptでもクラス(のようなもの)を定義してオブジェクトを作成できるようですが、サブクラスを定義する方法が分かりません。メソッドやコンストラクタはどのように継承すればよいのでしょうか。 お分かりの方おられましたら、ご教授のほどお願い致します。

  • mone
  • お礼率70% (80/114)

質問者が選んだベストアンサー

  • ベストアンサー
  • leaz024
  • ベストアンサー率75% (398/526)
回答No.3

JavaScriptにはクラス定義がないので、プロパティとメソッドを動的に継承しなければなりません。 プロパティは、コンストラクタから親のコンストラクタを呼び出すことで継承します。 ただし、その際 this のメソッドとして呼ばないと、親コンストラクタでの初期化が自分に反映されません。親コンストラクタをメソッドとして呼び出すには、 > call(または apply)メソッドを使い、「親コンストラクタ.call(this, 引数...)」とする。 または > 一時的に親のコンストラクタをプロパティに登録し、実行後に削除する。 という方法を取ります。 メソッドは、親の prototype を自分の prototype にコピーすることで継承します。 ただし、prototype はオブジェクトなので単に代入すると親のものを参照するようになってしまい、メソッドの追加などが親にも影響してしまいます。この問題の解法としては、 > for - in で prototype のプロパティを1つ1つコピーする。 とか > 親のインスタンスを作り、それを prototype に代入する。 というような方法が知られています。 しかし、for - in ではビルトインオブジェクトなどが持つ内部プロパティまでは取れないので、汎用的な継承の手段としては今ひとつです。 また、親のインスタンスを使う方法には余計な親コンストラクタ呼び出しが伴うので、親コンストラクタでクラスプロパティの変更などをしていると問題が生じます。 この問題を回避するには、親クラスと同じ prototype を持ち、コンストラクタでは何もしないダミークラスを定義して、そのインスタンスを prototype として使うようにします。 例:Base クラスを継承して Deriv クラスを構築する。 /**** class Base ****/ // コンストラクタ function Base(a) {   ++Base.count;    // 生成したBaseオブジェクトをカウント(親クラスを直接使って継承すると、問題が起こる例)   this.a = a; } // メソッド定義 Base.prototype.print = function () {   document.write("a=",this.a, "<br>"); } /**** class Deriv ****/ // コンストラクタ function Deriv(a, b) {   // プロパティの継承   Base.call(this, a);   // 固有プロパティの追加   this.b = b; } // メソッドの継承 function DerivPrototype() {}            // 継承用ダミークラス DerivPrototype.prototype = Base.prototype;  // プロトタイプは代入でOK Deriv.prototype = new DerivPrototype; Deriv.prototype.constructor = Deriv;      // コンストラクタまで変更されてしまうので修正 // メソッド定義 Deriv.prototype.print = function () {       // print のオーバーライド   document.write("a=",this.a, ", b=",this.b, "<br>"); } このコードで気になるのは、メソッド継承の部分だけ抽象レベルが低いことでしょう。単に関数化するだけでも見通しは良くなりますが、次のように全ての関数の上位クラスである Function のメソッドとして登録すると、さらに可読性が高まります。 Function.prototype.inherit = function (baseClass) {   function tempClass() {}   tempClass.prototype = baseClass.prototype;   this.prototype = new tempClass;   this.prototype.constructor = this; } このコードをクラス定義の前に記述しておき、継承の部分は次のように変更します。 Deriv.inherit(Base); ※インデントなどに全角空白を使っているので、コピーする場合はタブなどに置換して下さい。

mone
質問者

お礼

ご回答ありがとうございます。 詳細な解説とサンプルのおかげで、問題点なども含めた非常に深い知識と、大変高度なテクニックを学ぶことができました。 どうもありがとうございました。

その他の回答 (2)

  • BLUEPIXY
  • ベストアンサー率50% (3003/5914)
回答No.2

こんな感じ ------------------------------------------------------------- //Animalクラス //コンストラクタ function Animal(name, kind){ this.name=name; this.kind=kind; } //メソッド Animal.prototype.hey=function(){ return "I'm a " + this.name; }; Animal.prototype.toString=function(){ return "{" + this.name + " of " + this.kind +"}"; }; //Catクラス/Animalサブクラス function Cat(name){ this.name=name; this.kind="CAT"; } Cat.prototype=new Animal("","");//継承にあたる Cat.prototype.constructor=Cat;//コンストラクタは自分のを使う //新しいメソッド Cat.prototype.sing=function(){ return "nya-o"; };

mone
質問者

お礼

ご回答ありがとうございます。 分かりやすいサンプルにより、JavaScriptでのクラスの理解が一層深まりました。 どうもありがとうございました。

  • JeanneNet
  • ベストアンサー率48% (100/208)
回答No.1

こんにちは、じゃんぬねっと です。 子Class.prototype = new 親Class; http://www.parkcity.ne.jp/~chaichan/src/javascnew04.htm

mone
質問者

お礼

ご回答ありがとうございます。 提示して頂いたURLなど、大変参考になりました。 どうもありがとうございました。

関連するQ&A

  • PHPでの継承について

    PHPの継承についての質問です。 PHPではクラスを継承する場合 スーパークラスのpublicとprotectedなメンバを継承すると いいます。 継承とは、スーパークラスで定義したメンバが サブクラスで定義されたことと同義である。 という前提で質問します。 ひょっとしたらこの前提も微妙に間違っているかもしれません。 以下の用なコードがあるとします。 <?php class AClass { //サブクラスへ継承されるスーパークラスのメソッド public function superClassPublicMethod(){ //【1】 $this-> subClassPrivateMethod(); } } class BClass extends AClass{ public function subClassPublicMethod(){//【2】 $this->subClassPrivateMethod(); } //継承したスーパークラスで定義されているメソッドからコールするサブクラスで定義したメソッド private function subClassPrivateMethod(){ //【3】 print __CLASS__; } } $obj = new BClass(); //サブクラスで定義した public なメソッドを実行 $obj->subClassPublicMethod(); //【4】 //スーパークラスから継承したpublic なメソッドを実行 $obj-> superClassPublicMethod();//【5】 ?> コレを実行すると【4】はきちんとBClassという結果が返ってきます。 ところがその下の【5】を実行すると Fatal error: Call to private method BClass::subClassPrivateMethod() from context 'AClass' in /usr/local/apache/htdocs/ext06.php on line 9 という実行時エラーが返ってきます。これを読むと、AClassのコンテキスト内ではBClassのprivateなメンバは コールできませんよ。というエラーですね。そもそもAClassのコンテキストということは、これはAClass内で実行されているということですよね? ここで、スーパークラスからこのpublicなメソッドは継承しているはずなのになぜ、サブクラスのBCLass内ではなくスーパークラスのAClass内という エラーが返っているのでしょうか? 継承とは、サブクラスで定義したと同義ではなく、スーパークラスまで内部的にアップキャスト?してコールしにいっているのでしょうか? 詳しい方ご教授ください。 よろしく御願いします。

    • ベストアンサー
    • PHP
  • 継承について

    下の質問の回答、間違ってませんか? -------------------------------------------- 親クラスのフィールドをメソッドを全て継承することになります。よって、サブクラス2は、サブクラス1とスーパークラスのメンバーを全て持つことになります。サブクラス2をインスタンス化すると、サブクラス1とスーパークラスが全てインスタンス化(コンピューターのメモリ上等に配置)されます。 ただ、可視性というものがあり、サブクラスから親クラスのメンバーを直接取り扱えない場合があります。privateや可視性修飾子無しの場合、サブクラスから直接取り扱えません。ただ、継承はされているので、インスタンスとしては存在します。例えば、 class スーパークラス{ private int abc; public int getAbc(){ return this.abc; } というクラスがあり、これを継承したサブクラスがあったとします。 サブクラスからは、privateなメンバー変数abcは直接取り扱うことができません。ただ、publicなgetAbcメソッドはサブクラスから取り扱えます。これで何が分かるかといいますと、privateなメンバーでもサブクラスに継承されるのです。単に可視性の問題で直接取り扱えないだけなのです。 また、オーバーライドされたメソッドがあったとしても、super.メソッド()で親のメソッドも呼べますので、これも継承されているのです。

  • 継承について(長文です)

    いつもお世話になっています。現在、継承についての練習問題を解いているのですがわからないことがあるので質問させていただきます。 問題は、「自己紹介メソッド(抽象メソッド)を持つIntroduceクラスを作成し、そのクラスを継承してFistsNameクラス、FullNameクラス、IncludeAgeクラスを作成しなさい。三つのサブクラスのインスタンスを混合して配列に保持し自己紹介をしなさい」というものです。 それぞれのクラスはコマンドライン引数で名字(引数一つ)だけ、フルネーム(引数二つ)、フルネームと年齢(引数三つ)と3種類の引数を入力することによって適切なメソッドが呼び出されるということです。(わかりにくい文章ですいません。例えばヤマダと入力すればFirstNameクラスの自己紹介メソッドが呼び出されてヤマダと表示させたいのです)引数をサブクラスに渡さないと行けませんが、まずコンストラクタで引数をサブクラスに渡す場合は引数を一つ(もしくは二つ)しか指定しなかったときはフルネームとフルネーム+年齢のクラスでコンパイルエラー(ArrayIndexOutOfBoundsException)が出ます(これは理解することが出来ます)次にメソッドで渡す場合はシグネチャが異なるのでオーバーライドされずこちらもコンパイルエラーとなります。この他に引数をサブクラスに渡す方法はあるのでしょうか? わかりにくい文章になってしまいましたが、要するに三つのサブクラスをインスタンス化しその後、引数の個数により適切なサブクラスのメソッドが呼び出され引数を連結して表示させたいのです。このようなことは実現できないのでしょうか?if節によって引数の個数で場合分けなどをしないといけないのでしょうか?質問文がわかりにくければ補足させていただきます。よろしくお願いします。

    • ベストアンサー
    • Java
  • Javascriptでオブジェクト思考は可能でしょうか?

    Javascriptでオブジェクト思考は可能でしょうか? クラスを作成して、変数を隠ぺいして、コンストラクタ・メソッドとか 継承などできるのでしょうか? 簡単なサンプルがあれば助かります。

  • スレッドセーフなクラスのサブクラスは? synchronizedって継承先では?

    1)メソッドにsynchronizedキーワードをつけた時、継承先のサブクラス側でもsynchronizedは生きているのでしょうか? 2)もし生きていると サブクラス側で、synchronizedをとりけしたい場合 synchronizedをつけない形でオーバーライドして 中身の実装は super.メソッド名(); だけにするという方法しかないということでしょうか? 3)なお、 サブクラス側で、synchronizedキーワードを追加しながら メソッドのオーバーライドができるということは 知っています。 4) (1)の答えが生きていない。とすれば・・。 スレッドセーフなクラスをがんばって作成しても、 サブクラス作成者がいちいち意識しなければ、 サブクラスはスレッドアンセーフになってしまう ということでしょうか? サブクラス作成者がたとえ、赤の他人でまったく、 コミュニケーションをとれない状況であろうとも、 そうならないようにするためのしかけを 作るためのテクニックはあるでしょうか? なお、これはクラスをfinalしたくない場合の話です 以上です。

    • ベストアンサー
    • Java
  • 継承(extends)について

    extendsについてわからないことがあります。 次の3つのクラスがあった時、 class スーパークラス { ... class サブクラス1 extends スーパークラス { ... class サブクラス2 extends サブクラス1 {... サブクラス2は、サブクラス1でスーパークラスから継承しているフィールドをメソッドを継承するのでしょうか?

    • ベストアンサー
    • Java
  • 継承における暗黙のデフォルトコンストラクター

    ”継承の際、スーパークラスで引数なしのコンストラクターが省略せずにきちんと記述されるなら、そのサブクラスでコンストラクターを記述しなくても、スーパークラスの引数なしのコンストラクターが受け継がれるためコンパイルエラーがおきない。”のは分かりますが”スーパークラスで引数なしのコンストラクターが省略され、かつサブクラスでコンストラクターを省略した場合”はなぜコンパイルエラーがおきるのでしょうか? 暗黙の内にスーパークラスにコンストラクターが生成され、それがサブクラスに受け継がれることは出来ないのでしょうか? 宜しく願います。

  • ~クラスのメソッドと言った場合継承したものを含むか

    お世話になります。 OJC-Pの勉強中、以下の模試問題が出題されました。 ------------------- Threadクラスのメソッドとして正しいものを全て選びなさい wait() notify() run() start() ------------------- 解答はrun()、start()の2つだったのですが、 この場合、Objectクラスから継承したメソッドは Threadクラスのメソッドとは言わないのかを疑問に感じました。 (外部クラスから見た場合、 継承したメソッドもThreadクラスで新しく定義されたメソッドも区別は ないのでは、と考えたためです。) 問題文の表現に不備があるのでしょうか、 それともやはり 「~クラスのメソッド」と言った場合、継承したものは含まないとするのが 一般的な解釈なのでしょうか。 また、後者の場合、それはどうしてなのか理由なども添えていただけると 嬉しいです。 よろしくおねがいいたします。

    • ベストアンサー
    • Java
  • super( )メソッドについて質問です

    サブクラスのコンストラクタの定義をするときにsuper()メソッドを使うときはどういうときですか?また、どうしてsuper()メソッドを使って、スーパークラスのインスタンスを作成しないといけないのですか?教えてください。

    • ベストアンサー
    • Java
  • 【PHP】クラスを継承した際にデータ型も継承すると

    とある有料のオンライン学習サイトをつかっています。 学習項目の流れは以下の通りです。 現在「15 型の継承について見ていこう」で躓いています。 01 オブジェクトを使ってみよう (02:56) 02 投稿に関する処理を作ろう 03 クラスでデータ型を定義しよう 04 インスタンスを作ってみよう 05 コンストラクタを使ってみよう 06 クラスを整理しておこう 07 アクセス修飾子について見ていこう 08 メソッドを介してプロパティを操作しよう 09 プロパティで型宣言をしてみよう 10 staticキーワードを使ってみよう 11 オブジェクト定数を使ってみよう 12 クラスを継承してみよう 13 子クラスで独自の実装をしていこう 14 メソッドをoverrideしてみよう 15 型の継承について見ていこう *型の継承 *型を継承するメリット この項目で記述されているソースコードは下記のとおりです。コード内のクラス、SponsoredPostは クラスPostを継承しています。よって両方のクラスともにPost型として扱えると説明があります。 ソース内のこの箇所で processPostという関数を作成し、変数$postにPost型と型付けをしています そしてforeachでPostで型付けられた$post型(クラスPostとそれを継承したクラスSponsoredPost)をひとつづつ取り出し、processPostを用いてそれぞれにshow()メソッドで表示させています。 ----------------------- <?php class Post{ protected $text; public function __construct($text){ $this->text = $text; } public function show(){ printf('%s',$this->text); } class SponsoredPost extends Post{ private $sponsor; public function __construct($text, $sponsor){ parent::__construct($text); $this->sponsor = $sponsor; } public function show(){ printf('%s by %s', $this->text, $this->sponsor); } } $posts = []; $posts[0] = new Post('hello'); $posts[1] = new Post('hello again'); $posts[2] = new SponsoredPost('iPhone','Apple'); function processPost(Post $post){ $post->show(); } foreach($posts as $post){ processPost($post); ------------- クラスを継承すると親クラスのプロパティやメソッドが子クラスに継承されるというのは理解できています。「15 型の継承について見ていこう」という項目では 『Post型の変数を受け取る関数を作って、データ型が継承されることを説明していきます。』 と解説してあります。 クラスを継承すると親クラスのプロパティやメソッドが子クラスに継承されるというのは理解できています。私の知っているデータ型(文字列型、整数型、浮動小数点数型、論理型、配列型、オブジェクト型、リソース型、NULL)は下記の2か所だけです。 show()メソッド内の、['%s']と['%s by %s']で文字列が指定されています。 したがってこの項目で説明されている 『Post型の変数を受け取る関数を作って、データ型が継承されることを説明していきます。』 とは、「クラスを継承する際にプロパティやメソッドだけでなく、データ型、ここでは(['%s']と['%s by %s'])も継承されるということが説明されているという解釈でよろしいのでしょうか? 少し混乱しています。もし私の解釈が間違っているようでしたら教えてください。 初学者です。よろしくお願いいたします。 <表示結果>

    • ベストアンサー
    • PHP

専門家に質問してみよう