Javascriptにおけるクラシカルな継承

21

9月

2011

Javascriptの継承の勉強。本は「Javascriptパターン」。

なにがクラシカルというと、Javascriptにはクラスという概念がない。
ただし、Javascriptにはコンストラクタ関数やnew演算子があるのでクラスに似たような仕組みを作ることが可能です。
この”クラスに似たような仕組み”を「クラシカル」とし、クラスについて考慮する必要がない継承を「モダン」としています。
モダンについてはまた後日。。

「Javascriptパターン」によると、
クラシカルな継承パターンは色々とあるようですが、まとめると3パターンになります。
※ここではクラスに似た方法を記述するため敢えて「クラス」という言葉を使用しています。

デフォルトパターン

function Parent(name){
	this.name = name || "Adam";
}
Parent.prototype.say = function(){
	return this.name;
}

function Child(name){}
Child.prototype = new Parent();

var a = new Child('A');
alert(a.say()); // "Adam"

このパターンは子クラスのprototypeに親クラスのインスタンスを入れるという方法です。
個人的には一番メジャーな継承方法という印象です。実際使用していました。

このパターンの大きなデメリットは子クラスから親クラスへパラメータを渡すことができません。
つまり親クラスの初期化ができません。

プロトタイプを拝借

function Parent(name){
	this.name = name || "Adam";
}

function Child(){
	Parent.apply(this,arguments);
}
Child.prototype = new Parent();
var c = new Child('C');
alert(c.say()); // "C"

このパターンは、親のコンストラクタを子クラスのコンテキストで実行することで、子クラスから親クラスへパラメータを渡すことを可能にしています。このパターンであれば親クラスの初期化が可能になります。
欠点は親コンストラクタが2回呼ばれてしまうことです。
そのためプロパティを削除しても子のプロパティが削除されるだけで、親のプロパティは削除されずデフォルトの値が呼び出されてしまいます。

delete c.name;
alert(c.say()); // "Adam"

 

klass

var klass = function(Parent,props){
    var Child,F,i;
    Child = function(){
    	if(Child.uber && Child.uber.hasOwnProperty("__construct")){
		Child.uber.__construct.apply(this,arguments);
	}
	if(Child.prototype.hasOwnProperty('__construct')){
		Child.prototype.__construct.apply(this,arguments);
	}
    }

    Parent = Parent || Object;
    F = function(){};
    F.prototype = Parent.prototype;
    Child.prototype = new F();
    Child.uber = Parent.prototype;
    Child.prototype.constructor = Child;

    for(i in props){
    	if(props.hasOwnProperty(i)){
		Child.prototype[i] = props[i];
	}
    }

    return Child;
}

var Man = klass(null,{
    __construct : function(what){
	console.log("Man's constructor");
    	this.name = what;
    },
    getName : function(){
	return this.name;
    }
});

var first = new Man('Adam');
alert(first.getName());

var SuperMan = klass(Man,{
    __construct : function(what){
    	console.log("Super's constructor");
    },
    getName : function(){
    	var name = SuperMan.uber.getName.call(this);
	return name;
    }
});
var clark = new SuperMan('Clark Kent');
alert(clark.getName());

最後にklassという方法。もっともクラスに近い継承パターンです。
klass関数のパラメータは2つあり、1つめは継承される親クラスになり、なければObjectが継承されます。
2つめは新しいクラスの実装オブジェクトです。
klass関数ではコンストラクタは必ず「__construct」というメソッドでなければならない命名規則があります。
「__construct」以外は新たなプロパティ・メソッドを追加することができます。



Tags:Javascript

コメントをどうぞ

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

*

次のHTML タグと属性が使えます: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

トラックバック:http://blog.orangemittoo.net/post/js_extend_classic/trackback/