javascriptでスーパークラスのメソッドを簡単に呼び出したかった。それだけだった。
var Class = inherit(SuperClass, {hoge: ...});
作ったクラスはprototypeに、第二引数のオブジェクトがコピーされたスーパークラスのインスタンスを持つ。
第一引数がnullだと、スーパークラスにObjectを用いる。つまり、
var Class = inherit(null, {hoge: ...});
は
var Class = inherit(Object, {hoge: ...});
と同等となる。
また、第一引数が"prototype"をメンバに持たない普通のオブジェクト、つまり、
var Class = inherit({hoge: ...});
だと
var Class = inherit(Object, {hoge: ...});
と同等となる。
var obj = new Class({hoge: ...});
でインスタンスを作ると、引数のオブジェクトのコピーを持つオブジェクトとなる。
また、メソッド"initialize"が自動的に実行される。
ただし、コンストラクタに引数を渡さなかった場合は、initializeは実行されない。
this.superapply(arguments);
としてスーパークラスのメソッドを呼べる。第一引数は呼び出すメソッドの引数の配列とする。
このとき、呼び出し側のメソッドはコンストラクタやinheritでオーバーライドしたメソッドでなくてはならない。これは呼び出し側のメソッド名を記録する必要があるためである。
そうでない場合は第二引数にメソッド名を渡す必要がある。
var obj = new Class({}); obj.foo = function(){ this.superapply(arguments); // X this.superapply(arguments, "foo"); // O };
<html><head> <script type="text/javascript"> function inherit(superclass, override) { if (!superclass) superclass = Object; if (! "prototype" in superclass) { override = superclass; superclass = Object; } var that; var func; function superapply(arg, name) { var prev = {that: that, func: func}; try { var my = this.superapply; if (!arg) arg = []; if (!name) name = arguments.callee.caller.caller.methodName; if (that && func && (!name || name == func.methodName)) { that = that.superapply.obj; name = func.methodName; } else if (name) { that = my.obj; func = arguments.callee.caller.caller; func.methodName = name; } else { throw new Error("methodName is null"); } var result; if (func === that[name]) { result = this.superapply(arg, name); } else { func = that[name]; func.methodName = name; result = func.apply(this, arg); } } finally { that = prev.that; func = prev.func; } return result; }; var prototype = new superclass(); prototype.superapply = function(){superapply.apply(this, arguments)}; prototype.superapply.obj = superclass.prototype; if (override) for (var i in override) { prototype[i] = override[i]; if (typeof override[i] == "function") prototype[i].methodName = i; } var subclass = function(obj) { this.superapply = function(){superapply.apply(this, arguments)}; this.superapply.obj = prototype; if (obj) { for (var i in obj) { this[i] = obj[i]; if (typeof obj[i] == "function") this[i].methodName = i; } this.initialize(); } }; subclass.prototype = prototype; subclass.prototype.constructor = subclass; return subclass; } var C1 = inherit(Object, { fn: "C1", initialize: function(){ alert("C1.initialize"); this.second(this.fn); }, second: function(a){ alert("C1.second: "+a); } }); var C2 = inherit(C1, { fn: "C2", initialize: function(){ alert("C2.initialize"); this.superapply(); // }, //second: // function(a){ // alert("C2.second: "+a); // this.superapply([a]); } }); var C3 = new C2({ fn: "C3", //initialize: // function(){ // alert("C3.initialize"); // this.superapply(); // }, second: function(a){ alert("C3.second: "+a); this.superapply([a]); } }); </script> </head><body> </body><html>
methodNameなんとかならんもんか。