【翻訳】シンプルJavaScript継承

カテゴリ:Javascript関連 2013年3月16日 10:00

更新履歴

[13/03/17]
@hokacchaさんにいくつか指摘され、それを元に「今風」の書き方のものをアップしてみました。

だいぶ記事の更新がなくなっていて、久々の更新です。
最近ではHTMLやCSSを書く機会が少なく、もっぱらJSしか書いていません( ;´Д`)
ということで、これからはJSネタが中心になりそうです。

さて、今回はjQueryの制作者であるJohn Resigさんが考案したシンプルなクラス風継承を実現するJavaScriptコードを紹介したいと思います。
さらに最近では英語を勉強しているので、彼のブログ記事の翻訳に挑戦しつつ紹介したいと思います。(本人の許諾を得ています)
原文はこちら

シンプルなJavaScriptの継承

私はたくさんの仕事をしてきて、最近はJavaScriptの継承を使用しています。-- つまり、執筆中のJavaScript本の中で --
そしてその中でいくつかの実験的なJavaScriptによるクラス継承のシミュレーションテクニックを使っています。
私が見てきたすべてのもののうち、私がもっとも好きな base2 と Prototype から実装方法を借りました。

それらのテクニックの中からコアな部分を取り出して、シンプルで、再利用性とできるだけ分かりやすく、依存性がないようにまとめました。
加えて、シンプルでとても使いやすくなるようにしました。以下はどうやってそれを使うかのサンプルです。

  • コンストラクタの生成はシンプル(このケースではinitメソッドによってシンプルに実装されています)
  • 新しいクラスを作成する場合、既存のクラスから(サブクラスに)継承する必要があります。
  • すべてのクラスはひとつの祖先(Class)からなります。従って、新しいクラスを作成する場合はClassクラスから派生させる必要があります。
  • そしてもっともチャレンジングなことは、オーバーライドされたメソッドを提供していることです(同じコンテキストのプロパティから)。this._super()を使うことで、上記の、Personスーパークラスのinit()とdance()メソッドを呼ぶことができます。

この結果はとても喜ばしいものです。クラス構造の概念を実現すること、メンテナンスをシンプルにすること、そしてスーパークラスのメソッドを呼ぶことを可能にするのにとても役立ちます。

シンプルなクラス生成と継承

ここに実装を載せます。(リーズナブルなサイズとコメント入りです)- フィードバックはとても歓迎です。

2つのもっともトリッキーな私の意見は、初期化時にinitメソッドを呼ばないことと、_superメソッドを作ることです。これらがなにを行なっているのか、簡単に説明しましょう。

初期化

まず最初に、prototypeを使った正統な継承方法を見てみます。
上記の手法を使わない場合は以下のようになります。

上記の処理がなにをしているかというと、instansofに本当に望んでいることはインスタンス化とPersonオブジェクトのコンストラクタを呼ぶだけではありません。 これを構築するとき、initializing変数がtrueに設定されている場合の唯一の目的はprototypeを使用してインスタンス化を行うことです。

従って、実際にコンストラクタを呼ぶ場合は初期化モードではないことを確認し、同時にinitメソッドを呼び出します。

特に大事なことは、initメソッドへコストのかかるスタート時の処理(例えば、サーバへの接続、DOMの生成)を回避し、結果的に効率的にインスタンス化を行うことができます。

Superメソッド

継承を行うとき、スーパークラスから機能を継承してクラスを作成するとき、オーバーライドされたメソッドへ頻繁にアクセスしたいと思うでしょう。
最終的に、この特殊な実装の新しい一時的なメソッド(._super)はサブクラスのメソッドからのみアクセスでき、スーパークラスのメソッドを参照することができます。

例えば、もしスーパークラスのコンストラクタを呼び出したい場合、このテクニックで以下のように実現することができます。

この機能的な実装は、いくつかのステップを踏みます。
始めに、オブジェクトリテラルは、新しいPersonインスタンス(このコンストラクションについては以前触れられている)に必要な、既存のクラスの拡張に使われます(Person.extendで渡されているような)。

このマージ時に、簡単なチェックを行います。プロパティの場合はのマージを試みるか、あるいは、関数の場合は置き換えるか。もし関数の場合、スーパーメソッドが動作する方法が必要になります。

とても強力なメソッドをカプセル化する、匿名のクロージャー(関数を返すもの)を作成します。 クロージャーの実行時、正常に振る舞うように古いthis._superの参照を(それがあるかどうかを無視して)保存し、クロージャーの実行終了後、それを元に戻します。 これは、同名の変数がすでに存在していた場合に(誤って上書きしないように)役立ちます。

次に、既存のスーパークラスのprototypeへの参照を持っている新しい _super メソッドを作ります。
ありがたいことに、それがオブジェクトのプロパティである場合functionは自動的にコンテキストが設定され、他の追加の変更や再スコーピングをする必要はありません。(生成されたインスタンスはスーパークラスへの参照を持ちます)

最後に、オリジナルのメソッドをコールするとそれ自身の処理を行い、その後_superを元の状態に戻し、処理結果を戻します。

今ではいくつかの同様な(上記のような)結果を得る方法があります。(arguments.calleeからアクセスできるsuperメソッドをメソッドにひもづける実装を見て来ました)しかし、このテクニックがユーザビリティとシンプルさを兼ね備えたベストな方法であると思っています。

完成した作品の中で、JavaScriptのプロトタイプシステムの裏に隠された、もっとたくさんの核心について触れたいと思っています。しかし、みなさんにこれを試し、使ってもらうためにこの「クラス」の実装を見せたいと思っていました。
単純化したコードからはたくさんの学びがあると思います。(学習しやすく、拡張しやすく、ダウンロードしやすい)そう、つまりこの実装はJavaScriptのクラス構築と継承の基礎について学び始めるのにとてもいい場所だと思っています。

この記事のカテゴリー一覧を見る⇒Javascript関連

  • このエントリーをはてなブックマークに追加

トラックバックURL

http://css-eblog.com/cgi-bin/mt/mt-tb.cgi/211