Bonjour à tous. :-)
(mon premier poste)

J'ai décidé, il y a quelques jours, de créer de l'héritage en javascript. (juste pour le fun, car aucune utilité apparente.) J'ai donc commencé par chercher les différentes version existantes sur la toile mais celles que j'ai trouvé semblaient "mal" fonctionner. Je me suis donc dis que je pouvais m’atteler à la tâche sans craindre de refaire ce qui existe déjà.

Bref, voici mon code (qui devra certainement être amélioré).

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
 
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 un bout de code pour le tester sommairement :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
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");

Voila, j'attend vos opinions avec impatience : Ca ne sert à rien ? Ca ne fonctionne pas ? Ca existe deja ? C'est une bonne idée à améliorer ? Suggestions ?

Bonne lecture et merci pour votre attention.



PS: code peu commenté mais j'ai essayé de le faire lisible .. puis y'a les tests pour le resultat. Car c'est ce qui compte in fine.