最近、プロトタイプ的継承の話しが盛り上がっています。
最終形がやたら複雑になっています
でも、実際はあそこまで複雑に書かなくても、できると思います ^^;
そう思う理由
というわけで、僕も作ってみた。
toSource に対応してみた。あと、関数オブジェクトはクローンすると[[Call]]できなくなるので、同じ動作をする別のオブジェクトを返すようにした。undefined の場合と null の場合はそのまま返す。
// Executable
var clone = function(p) {
p = (function(){return this}).apply(p); // objectify if atomic
switch (typeof p) {
case 'function': return function() { return p.apply(this, arguments) };
case 'undefined': return p;
case 'object':
if (p == null) return p;
else {
var f = function() {};
f.prototype = p;
var o = new f;
switch (p.constructor) {
case String: case Number: case Boolean:
if (o.toSource) o.toSource = function() { return "clone(" + p.toSource.apply(p, arguments) + ")/*require clone function*/" };
o.toString = function() { return p.toString.apply(p, arguments) };
o.valueOf = function() { return p.valueOf.apply(p, arguments) };
}
return o;
}
}
};
動作確認
普通のオブジェクト
// Executable
var a = {};
var b = clone(a); // b のプロトタイプチェーンには a が継っている
a.hoge = 'fuga';
alert(b.hoge); // fuga と表示される
b.hoge = 'piyo';
alert(a.hoge); // fuga と表示される
数値をプロトタイプに繋げる。
// Executable
var a = 1;
var b = clone(a); // b のプロトタイプチェーンには a をオブジェクト化したものが継っている
b.addOne = function() { return this + 1 };
alert(b.addOne()); // 2
alert(a.addOne); // undefined
文字列をプロトタイプに繋げる
// Executable
var a = 'hello';
var b = clone(a); // b のプロトタイプチェーンには a をオブジェクト化したものが継っている
b.addAmachang = function() {return this + ' amachang'};
alert(b.addAmachang()); // 'hello amachang'
alert(a.addAmachang); // undefined
真理値をプロトタイプに繋げる
// Executable
var a = true;
var b = clone(a); // b のプロトタイプチェーンには a をオブジェクト化したものが継っている
b.toJapanese = function() {return this ? '本当' : 'うそ'};
alert(b.toJapanese()); // '本当'
alert(a.toJapanese); // undefined
実際にこの関数を使って new を使わないプロトタイプベースのオブジェクト指向を書いてみる。
もう、クラスベースみたいな new とかいらない!clone できるし!
// 動物のプロトタイプ
var animal = {
breath: function() {
alert('すーはー');
}
};
// 鳥さんのプロトタイプ
var bird = clone(animal);
bird.fly = function() {
alert('ばたばた');
};
// ペンギンさんのプロトタイプ
var penguin = clone(bird);
penguin.fly = function() {
alert('飛べない');
};
// ドンペン君
var donpen = clone(penguin);
donpen.sing = function() {
alert('どんどんどんどんきー♪ドンキーホーテー!');
};
donpen.breath(); // 動物だから呼吸できる
donpen.fly(); // ペンギンは飛べない
donpen.sing(); // ドンキホーテーの歌を歌う
// 実は鳥は歩ける
bird.walk = function() {
alert('てくてく');
};
donpen.walk(); // 鳥なので「てくてく」歩ける
// でも、ペンギンは「てくてく」じゃなく「ぴょこぴょこ」だ
penguin.walk = function() {
alert('ぴょこぴょこ');
};
donpen.walk(); // ぴょこぴょこ
これぞ、プロトタイプベースオブジェクト指向!
わーわー!まじで楽しい!