bon, la première ébauche ne ressemblait vraiment pas à grand chose, donc voici la version 2.0
ça gère maintenant l'héritage dans tous les sens (dans tous les sens du terme^^).
function searchInArray(arr,elem) {
if (Array.prototype.indexOf) return arr.indexOf(elem);
for (var i in arr) if (arr[i] === elem) return i;
return -1;
}
function __uber(fname,arg){
var c = arguments.callee;
while(c.caller != null && typeof(c.caller.from)=="undefined")
c = c.caller;
if(c.caller!=null)
var parentIndex = searchInArray(this.constructor.herited,c.caller.from)-1;
else
var parentIndex = this.constructor.herited.length-1;
while(parentIndex>=0 && !this.parentFN[this.constructor.herited[parentIndex]] )
parentIndex--;
if(parentIndex < 0)
throw fname+"() not found in parent constructors of current object.";
var func = this.parentFN[this.constructor.herited[parentIndex]][fname] ;
var arg = arg || [];
return func.apply(this,arg);
}
function __construct(obj){
if(__construct.caller!=obj.constructor) return; // prevent from recursive calls
for(var i=0;i<obj.constructor.herited.length;i++){// for(var i in obj.constructor.herited) will call Array.prototype and Object.prototype functions
try{ obj.constructor.herited[i].apply(obj,__construct.caller.arguments); }
catch(err) { throw "error to calling parent constructor : "+i+" ["+err+"]"; }
try{ __copyFunctions(obj,obj.constructor.herited[i]); }
catch(err) { throw "error to copying parent functions of : "+i+" ["+err+"]"; }
}
}
function __copyFunctions(obj,constructorParent){
obj.parentFN = obj.parentFN || {};
obj.parentFN[constructorParent] = {};
for(var i in obj) if(typeof(obj[i])=='object' || typeof(obj[i])=='function'){
obj.parentFN[constructorParent][i] = obj[i];
obj.parentFN[constructorParent][i].from = constructorParent;
}
}
Function.prototype.inherits = function(Parent){
if(this.herited)
eval("var newF = "+this.toString()); // newF = clone( this ); -> change on newF.prototype will not affect this.prototype
else{
var s = this.toString();
var b = s.indexOf("{")+1;
eval("var newF = "+s.substring(0,b)+"__construct(this);"+s.substring(b,s.length));
}
for(var i in Parent.prototype)
newF.prototype[i] = Parent.prototype[i];
for(var i in this.prototype)
newF.prototype[i] = this.prototype[i];
newF.herited = (this.herited?this.herited.slice(0):[]);
var H = (Parent.herited?Parent.herited.slice(0):[]) // = parent.herited[]
H.push(Parent); // = parent.herited[] + parent
newF.herited = H.concat(newF.herited) // = parent.herited[] + parent + this.herited[]
newF.name = newF.name || this.toString().substring(9,this.toString().indexOf('(')); // define Function.name property for IE || it's useless
//\\ this.name = this.name || this.toString().substring(9,this.toString().indexOf('('));
//\\ if(this.name!="(") // the next line will don't work on unamed function
//\\ eval(this.name+" = newF"); // uncomment thoses lines to overwrite "this" function, then when you call B.inherits(A) that'll make : B = newF;
newF.prototype.uber = __uber;
return newF;
};
Et voici qqes tests qui prouvent que le principal fonctionne :
var alert = function(val){document.write(val,"<hr>");};
function A(){this.a=1;this.aa=function(){alert("aa");};this.obj={val:97};this.hard=function(c){alert("a.hard: "+c);};}
A.prototype.fun = 11;
function B(name){this.b=2;this.bb=function(){alert("bb");};this.name=name;this.hard=function(v){alert("b.hard: "+v);this.uber("hard",arguments);};}
function O(){this.o=3;this.oo=function(){alert("oo");};}
function H(){this.h=4;this.aa=function(){alert("hh");};this.oo=function(){alert("hh");};}
H.prototype.fun = 22;
var B = B.inherits(A);
var H = H.inherits(B);
var H = H.inherits(O);
var h = new H("john smith");
alert("=============== FOR EACH IN ( h ) ===============");
for(var i in h) alert(i+": "+h[i]);
// a: 1
// b: 2
// o: 3
// h: 4
// func aa : alert hh
// func bb : alert bb
// func oo : alert hh
// parentFN : ############### object
// obj : object
// name : "john smith"
// uber : ############# function
// overwrited functions
alert("=============== OVERWRITED FUNCTIONS ===============");
h.aa(); // hh
h.oo(); // hh
alert("=============== SUPER/ORIGINAL FUNCTIONS ===============");
// super functions who been overwrited
h.uber("aa"); // aa
h.uber("oo"); // oo
alert("=============== HERITED FUNCTIONS ===============");
// herited function
h.bb(); // bb
alert("=============== OBJECTS FROM 2 DIFFERENT INSTANCES ===============");
// test if object1.obj != object2.obj
var h2 = new H();
h2.obj.val++;
alert(h2.obj.val); // 98
alert(h.obj.val); // 97
alert("=============== PARENTS PROTOTYPE AREN'T MODIFIED ON CHANGE OF CHILD PROTOTYPE ===============");
var a = new A();
alert(a.fun);
alert(h.fun);
alert("=============== FINAL TEST ===============");
h.hard("Happy End");
Toujours personne pour donner son opinion ?
edit: version 2.2 (code légèrement nettoyé et optimisé)[/i][/i][/i][/i][/i][/i][/i][/i][/i][/i][/i][/i][/i]
Modifié par bogs (29 Dec 2010 - 16:32)