このブログの更新は Twitterアカウント @m_hiyama で通知されます。
Follow @m_hiyama

メールでのご連絡は hiyama{at}chimaira{dot}org まで。

はじめてのメールはスパムと判定されることがあります。最初は、信頼されているドメインから差し障りのない文面を送っていただけると、スパムと判定されにくいと思います。

参照用 記事

プログラマのためのJavaScript (号外):こんな継承はどう?

昨日の「プログラマのためのJavaScript (11):継承についてもう少し」に、いくつかのコメントをいただきました。そのなかで、nanto_viさんに素晴らしいヒントを提供していただいたので紹介し、クラス(もどき)の継承への補足とします。

まずは、nanto_viさんが教えてくれたコードを再掲:


var Traits = function () {};
Traits.prototype = SuperClass.prototype;
SubClass.prototype = new Traits();

Traitsは一時的なコンストラクタですが、SuperClassのトレイツ(共通性質の定義)をそのまま持ち、余分な(おそらくは弊害を生むであろう)初期化実行コードは持たないものです。(こんなトリックがあったんだ、フーム、ムムム。)

この手続きを関数にしてみます。(ちなみに、名前extendsは予約されているからダメ。)


function inherits(Sub, Super) {
// 上記と同様なコード
}

そして、この関数を inherits(Sub, Super); と呼び出してもいいのですが、Function.prototype内に定義すると、Sub.inherits(Super); と書けるので、宣言っぽくて可読性が向上しそうです。

何度も使っている例、ColoredPoint extends Point をこの方法を使って書き直してみました。太字部分が継承実行コード(もちろん、本物の宣言ではない)ですが、随分みやすくていい感じだと僕は思うのですが、いかがでしょう。


Function.prototype.inherits = function(Super, copyStatic_, defineSuper_) {
// オプション引数 copyStatic_ :静的メンバーをコピーする
// オプション引数 defineSuper_:_superclass, _superを定義する

var Traits = function(){};
Traits.prototype = Super.prototype;
this.prototype = new Traits();
this.prototype.constructor = this;
if (copyStatic_) {
for (var p in Super) {
if (typeof this[p] == 'undefined') {
this[p] = Super[p]
}
}
}
if (defineSuper_) {
this._superclass = Super;
this._super = Super.prototype;
}
}

/*
* ========== クラスPoint ========== *
*/

/* クラスの定数 */
Point.MAX_X = 1000;
Point.MAX_Y = 1200;

/* クラス(静的)メソッド */
Point.checkBounds = function(x, y) {
if (Math.abs(x) > Point.MAX_X) {
throw new Error("out of bounds - x");
}
if (Math.abs(y) > Point.MAX_Y) {
throw new Error("out of bounds - y");
}
}

/* コンストラクタ */
function Point(x_, y_) {
if (typeof x_ == 'undefined') x_ = 0;
if (typeof y_ == 'undefined') y_ = 0;
Point.checkBounds(x_, y_);
/* インスタンス初期化コード */
this.x = x_;
this.y = y_;
}

/* インスタンスメソッド */
Point.prototype.moveTo = function(newX, newY) {
Point.checkBounds(newX, newY);
this.x = newX;
this.y = newY;
}
/* インスタンスメソッド(オーバライド) */
Point.prototype.toString = function() {
return "(" + this.x + ", " + this.y + ")";
}

/*
* ===== サブクラスColoredPoint ===== *
*/

/* 継承の宣言 */
ColoredPoint.inherits(Point, 'copyStatic', 'defineSuper');

/* 追加の定数 */
ColoredPoint.BLACK = 0;
// ... 色の名前が並ぶ

/* このクラスのコンストラクタ */
function ColoredPoint(color_, x_, y_) {
if (typeof color_ == 'undefined') color_ = ColoredPoint.BLACK;
// superconstructor call
ColoredPoint._superclass.apply(this, [x_, y_]);
this.color = color_;
}

/* メソッドのオーライド */
ColoredPoint.prototype.toString = function() {
// super method call
var s = ColoredPoint._super.toString.apply(this, []);
return s + "/" + this.color;
}

再度: nanto_viさん、どうもありがごうございました。