最近、プロトタイプ的継承の話しが盛り上がっています。
最終形がやたら複雑になっています
でも、実際はあそこまで複雑に書かなくても、できると思います ^^;
そう思う理由
というわけで、僕も作ってみた。
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(); // ぴょこぴょこ
これぞ、プロトタイプベースオブジェクト指向!
わーわー!まじで楽しい!