継承 : JavaScript

Pocket

Javaのextendsにあたる明示的な継承手段をJavaScriptは提供していない。ただ実質的に継承に相当する機能を実現する方法がいくつかある。

  1. 継承先のオブジェクトのprototypeプロパティに継承元のインスタンスを設定する方法。
  2. 親のthisプロパティーの継承はapply関数で行い、prototypeプロパティーはfor in文で行う方法。
  3. 『JavaScript: The Good Parts』 (pp59-63)のnew演算子を使わない方法。

方法1 prototypeプロパティに継承元のインスタンスを設定

継承先のオブジェクトのprototypeプロパティに継承元のインスタンスを設定する。

/*
 * 親 : Family
 * 子 : Self
 */
var Family = function () {
	this.familyName = '山田';
}
Family.prototype.getFamilyName = function () {
	return this.familyName;
}

var Self = function (value) {
	this.name = value;
}
// 継承
Self.prototype = new Family(); 
// Self.prototype = Family; ではダメ-----(1)
Self.prototype.getName = function () {
	return this.familyName + ' ' + this.name;
}

// インスタンスを作成
var my = new Self("太郎");
my.getName(); // 山田 太郎

prototypeにnew演算子で生成したインスタンスを設定する。
コンストラクタ(関数オブジェクト)を直接設定してもthisを参照できな点に注意する

問題点

  1. メンバへのアクセス制限ができない。
  2. スーパークラスへのアクセス方法がない。
  3. prototypeにインスタンスを設定するのがしっくりこない。
  4. 2012.02.21追記 親クラスが引数を取る場合は使えない。

方法2 apply関数, for in文による継承

一般にコンストラクタ(関数オブジェクト)から生成したインスタンス[1]は暗黙リンク[2]にコンストラクタ(関数オブジェクト)のprototypeプロパティが設定される。
継承を実現するには子インスタンスが親関数オブジェクトのprototypeプロパティを参照できればよい。

継承を実装

基本的には次のような方法で継承を実現することができる。

  • 親のthisプロパティー → apply関数による継承[3]
  • 親のprototypeプロパティー → for in文を使った親オブジェクトから子オブジェクトへのコピーによる継承
/*
 * 親 : ParentObject
 * 子 : ChildObject
 */

/*
 * 親 : ParentObject
 * 子 : ChildObject
 */

var ParentObject = function(value) {
    this.name = value;
};
ParentObject.prototype.family = '山田';
ParentObject.prototype.showFullName = function() {
    return this.family + ' ' + this.name;
};

var ChildObject = function(name, gender) {
    // thisプロパティを継承
    ParentObject.apply(this, [name]);
    // ChildObject固有のプロパティ
    this.gender = gender;
};
// prototypeプロパティを継承
for (var prop in ParentObject.prototype) {
    ChildObject.prototype[prop] = ParentObject.prototype[prop];
};
// 継承先のインスタンスを作成
var child = new ChildObject('小太郎', '男');
// 実行画面 アラートボックス
alert(child.showFullName() + ' : ' + child.gender);
// 山田 小太郎 : 男

Functionオブジェクトのapplyメソッドについては下記サイトに詳しい説明がある。
» JavaScriptのapplyヤバい – ++iskwn – キューイチ世代

方法3 :『JavaScript: The Good Parts』の方法

『JavaScript: The Good Parts』 (pp59-63)はnew演算子を使わない継承方法を紹介している。

var integer = function (spec, my) { 
    var that = {};         // パブリック 
    var my = my || {};   // プライベート 
    
    // パブリック 
    that.getValue = function () { 
        return spec.value; 
    } 
    return that; 
} 

var interger2Times = function (spec) { 
    var that = integer(spec); 
    that.getTimes = function () { 
        return spec.value * 2; 
    }
    return that; 
} 
    

var o = interger2Times({value: 3}); 
o.getValue();  // 実行結果 3
o.getTimes(); // 実行結果 6

Douglas Crockford著 水野 貴明訳 2008 『JavaScript: The Good Parts』 オライリー・ジャパン

プライベートメンバを設定した場合の例

var circle = function (spec, my) {
    var that = {};          // インスタンス
    var my = my || {};   // プライベート
    if  ( my.pi == undefined ) {
        my.pi = 3;
    } 
    // パブリックメンバ
    that.getArea = function () {
        return my.pi * spec.radius * spec.radius;
    }
    return that;
}

var strictCircle = function (spec, my) {
    var that = circle(spec, my);
    that.getCircumference = function () {
        return 2 * my.pi * spec.radius;
    }
    return that;

}

var o = strictCircle({radius: 3}, {pi: 3.14});
o.getAarea(); // 28.25999999…
o.getCircumference(); // 18.84

1. new演算子使ってインスタンスの生成に使われた関数オブジェクトをコンストラクタと呼ぶ。
2. 処理系によっては暗黙リンクを__proto__プロパティとして公開している。
3. applay関数については下記を参照。
» apply, call : JavaScript

コメント

No comments yet.

コメントの投稿

改行と段落タグは自動で挿入されます。
メールアドレスは表示されません。