11548 sujets

JavaScript, DOM et API Web HTML5

Bon voila, je m'e*******s (ennuyais) grave la semaine dernière au point de me dire "et si je créais du pseudo-héritage en javascript ?" ! Nous voila une semaine plus tard et je vous propose un premier jet de mon code :

http://xoboot.netai.net/inheritance/

Sur ma page, je compare mon coe à celui de la version de Crockford car de toutes les autres que j'ai pu voir, je trouvais la sienne la plus élégante de toutes. Mais hélas, la sienne, comme la plupart des autres, ne fonctionne pas bien du tout.

Ma version, étant un premier jet, comporte encore pas mal de bugs.
Par exemple, elle gère l'héritage de plusieurs niveau, comme suit :
B.herit(A); // B is A
C.herit(B); // C is B
Mais pas encore l'héritage multiple :
C.herit(A); // C has/is A
C.herit(B); // C has/is B

Voili voilou, vous en pensez quoi ? Ca vaut la peine de continuer ?
Merci d'avance pour vos avis. Smiley lol
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 ? Smiley lol

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)
UP.

toujours personne pour me donner un soupçon d'avis ?
-c'est inutile ?
-ça existe déjà en mieux ?
-des bugs ?
-suggestions d'optimisation ?
Modifié par bogs (29 Dec 2010 - 16:34)
Je sais pas si j'ai le niveau pour commenter ton code, donc je m'abstiendrais Smiley smile

Mais je pense que des choses pas mal existe déjà dans les frameworks javascript, par exemple mootools (moi j'aime bien mootools Smiley smile ) incorpore dans son frameworks le principe de language objet, donc de classe et d'héritage -> http://mootools.net/docs/core/Class/Class
(je te laisse regarder)

Cela dit, si tu te fais un challenge... continu ! Peaufine ton idée Smiley cligne
KalNex a écrit :
Je sais pas si j'ai le niveau pour commenter ton code, donc je m'abstiendrais Smiley smile

Mais je pense que des choses pas mal existe déjà dans les frameworks javascript, par exemple mootools (moi j'aime bien mootools Smiley smile ) incorpore dans son frameworks le principe de language objet, donc de classe et d'héritage -&gt; http://mootools.net/docs/core/Class/Class
(je te laisse regarder)

Cela dit, si tu te fais un challenge... continu ! Peaufine ton idée Smiley cligne

La plupart des solutions existantes ne font que soit hériter leurs propres objets ou font hériter grossièrement un objet d'un autre. généralement simple copie des prototypes et accès aux parents (uber/super) inexistants.

Il existe qqes exemples d'héritages de Classes ('Function') mais tous ceux que j'ai vu font de nouveau que de vulgaires copy de prototype... en instanciant un objet parent ce qui implique déjà 2 bugs avant même de commencer (tous les objets hérités auront le même prototype, donc si l'objet parent possédait un objet( une reférence vers un objet) ... ils auront tous des référence vers cette objet unique et non pas un différent chacun .. en modifier un, les modifient tous.) (un objet parent sera instancié pour créer le prototype même si on instancie jamais d'enfants ..) et beaucoup d'autres bugs selon les versions de chacun, bref voici mon héritage complètement retravaillé :

http://www.borisdessy.com/


De nouveau avis ? Smiley smile

edit: pour comparer à la methode de crockford qu'on peut trouver ici
voici, la même batterie de test appliqué dessus : http://www.borisdessy.com/crock.html
Modifié par bogs (11 Jan 2011 - 19:15)