Comportements étranges pour les classes - cherche réponses... (bonne version)

cs_nasian Messages postés 3 Date d'inscription lundi 25 août 2003 Statut Membre Dernière intervention 26 juillet 2004 - 5 juil. 2004 à 01:30
cs_nasian Messages postés 3 Date d'inscription lundi 25 août 2003 Statut Membre Dernière intervention 26 juillet 2004 - 26 juil. 2004 à 18:07
Salut à tous !

Je m'interrogeais sur les mécanismes des langages prototypés comme Flash.

Durant mes qq. tests je suis tombé sur deux phénomènes qui me paraissent étranges et auxquels je cherche des explications. Sur quoi je me suis dit que la meilleure place pour trouver un peu d'aide serait certainement ici ;)

*************************************************
QUESTION 1
*************************************************
Pourquoi après avoir supprimé une classe, la méthode publique de cette dernière est-elle toujours accessible par l'objet ?

CAS 1 – ligne 25 : je supprime la classe pour empêcher les objets de retrouver la référence de leur méthode init()

//-------------------------------
// CLASSE
function AClass(pName) {
this.constructor.xName = "AClass";
}
AClass.prototype.init = function(pName) {
this.xName = pName;
};
//-------------------------------
// INSTANCES
oObjet = new AClass();
oObjet.init("oObject before");
//
oObjet2 = new AClass("oObjet2");
oObjet2.init("oObjet2 before");
//
trace("");
trace(AClass.xName);
trace(oObjet.xName);
trace(oObjet2.xName);
//-------------------------------
// CLASSE DELETED
trace("\n----------");
trace("DELETE AClasse");
delete AClass;
oObjet.init("oObject after");
oObjet2.init("oObjet2 afert");
//-------------------------------
trace(AClass.xName);
trace(oObjet.xName);
trace(oObjet2.xName);


RÉSULTATS
AClass
oObject before
oObjet2 before
----------
DELETE AClasse
undefined
oObject after
oObjet2 after

La classe a bien été supprimée, mais les objets retrouvent toujours la méthode (changent leur nom de –before- à –after-).
Il me reste deux solutions, soit les objets ont dupliqué la méthode (comme ils le font pour les variables : composition semble-t-il), soit la méthode de la classe –AClass.prototype.init- existe toujours… (agrégation persiste alors que l’objet AClass n’existe plus…)

CAS 2 – je remplace la ligne 25 par
delete AClass.prototype.init

Le résultat change : les objets ne retrouvent pas le __proto__ de leur méthode init();
Leur nom (attribut) ne change donc pas.

RÉSULTATS
AClass
oObject before
oObjet2 before
----------
DELETE AClass.prototype.init
AClass
oObject before
oObjet2 before


QUESTION
Il semble donc qu’il n’y ait en effet pas de composition, donc comment ce fait-il qu’ayant détruit l’objet AClass, la méthode AClass.prototype.init persiste ?
Je dois faire une erreur de raisonnement qq. part, des suggestions ?

*************************************************
QUESTION 2
*************************************************
Une chose qui m’a étonné, j’ai fait les deux petits tests précédents sur deux frames et j’ai vraiment été surpris par le comportement des fonctions…

Aucune de ces 3 façons d’écrire ne donne les mêmes comportements…
-
 function maFn() {}

-
 maFn = function () {};

-
 nameSpace. maFn = function() {};


CAS 1 : frame 2 : je nettoie les objets de la frame 1 en les supprimant, je commence donc par supprimer AClass avant de la recréer.
Cependant dans ce cas, si, cela ne fonctionne pas, la classe que je définit ensuite n’est pas créée (ou supprimée ?)
delete Aclass;
//
function AClass(pName) {
this.constructor.xName = "AClass";
}


CAS 2 : écrite dans ce sens, la classe apparaît bien dans le debugger, mais dans l’héritage elle pose un problème (que je ne développerai pas ici)
delete Aclass;
//-------------------------------
AClass = function (pName) {
this.constructor.xName = "AClass";
};


CAS 3 : cette solution (forcer la référence dans un espace de nommage) est celle qui ne présente aucun problème de manipulation.
delete Aclass;
//-------------------------------
spaceName.AClass = function (pName) {
this.constructor.xName = "AClass";
};


QUESTION
Pourquoi une telle disparité de comportement selon la façon dont on déclare la fonction ???
Vraiment, je pense définitivement que quelque chose m’échappe…

*************************************************
RÉSUMÉ DES 2 Q.
*************************************************
CAS 1 – Aclass n’existe pas alors qu’elle le devrait, et l’objet existe alors qu’il ne le devrait pas…
delete AClass;
function AClass() {
trace("hello");
// 
function maFn() {
}
}
oObj = new AClass();


CAS 2 – Aclass existe, mais sa fonction privée (maFn) est sur le _root (cf. debugger)
delete AClass;
AClass=function () {
trace("hello");
// 
maFn = function () {
}
}
oObj = new AClass(); 

</td></tr></table>

CAS 2 – tout semble aller, mais il y a une disparité dans la façon d’écrire les fonctions selon si elles sont « nested » ou non….
delete AClass;
AClass=function () {
trace("hello");
// 
function maFn() {
}
}
oObj = new AClass();
 


CAS 3 – idem cas 2 - Aclass existe, mais sa fonction privée (maFn) est sur le _root (cf. debugger)
delete nameSpace
nameSpace = new Object();
//
nameSpace.AClass = function() {
trace("hello");
// 
maFn = function () {
}
};
oObj = new nameSpace.AClass(); 


CAS 4 – la solution « parfaite » … malgré la disparité de déclaration entre fonction englobante et fonction imbriquée…
delete nameSpace
nameSpace = new Object();
//
nameSpace.AClass = function() {
trace("hello");
// 
function maFn() {
}
};
oObj = new nameSpace.AClass(); 


QUESTION
Il semble donc qu’une fonction s’écrive deux façons différentes selon qu’elle est « nested » ou non….

Fonction « indépendante » ou classe :
nameSpace.AClass = function() {};


Fonction « nested »
function maFn() {}


POURQUOI TANT DE DIFFICULTÉES ????

Merci à ceux qui pourront m’aiguiller.

3 réponses

blackwizzard Messages postés 1258 Date d'inscription mercredi 21 mars 2001 Statut Membre Dernière intervention 21 juin 2009 2
16 juil. 2004 à 02:47
personnelement, tu me pose une colle...
les class as1, j'ai jamais vraiment touché... j'ai commencé les class sous as2 et c'est completement different...
si tu vx une reponses, je te conseil d'aller voir sur d'autres forums, car ici c'est pas du haut nivo, a part 2 ou 3 membres...
www.flash-forum.net est tres bien, c'est le board de media-box, reconnu officielement par macromedia...
[BlackWizzard] http://www.blackwizzard.net
0
cs_nasian Messages postés 3 Date d'inscription lundi 25 août 2003 Statut Membre Dernière intervention 26 juillet 2004
16 juil. 2004 à 15:30
Merci,

J'avais aussi posté sur www.flash-forum.net (http://flash.media-box.net/viewtopic.php?t= 29754), mais pas de réponse non plus...

Sinon, j'ai bien une petite piste, mais je n'ai pas encore eu le temps d'approfondir.

Il s'agirait (après qu'un ami m'ait mis la puce à l'oreille) d'une affaire d'allocation de mémoire. Il semblerait que les références ne soient pas supprimées et que, donc, en appelant une classe détruite, au lieu de renvoyer "undefined", il recrée le "chaînon manquant" et par la même la chaîne de dépendance entre les références... faut que je regarde plus avant.

Sinon, le bug qui n'en est pas un dans le cas 2:
AClass=function () {
    trace("hello");
    // 
    maFn = function () {
    }
}

oObj = new AClass();


maFn se retrouve sur le _root car en fait ce n'est pas une fonction privée mais bien une function définit dans une variable qui elle est sur le root

rappel :
var maVar = déclaration explicite
maVar == déclaration implicite (bad way in fact...)

C'est d'autant plus important dans une function
"var" rendant l'attribut privé (local et invisible, appartenant à la fonction) sinon l'attribut appartient au root automatiquement...

Et il en va de même pour les nested function :
il vaut mieux écrire
var maFn = function(){}
que
    maFn = function () {
    }

Et là encore.... ca pose un problème car flash fait plus l'auto-format correctement (normal, il prend la déclaration de fonction pour une variable, donc il fait p^lus les saut de ligne, et tout les commentaires de votre fonction disparaissent, vous pouvez essayer avec ca par exemple :
AClass = function () {
// 
var maFn = function () {
// mon commentaire
trace("Fn 2");
}
};


Maintenant, lancez l'auto-format (Ctrl+Shift+F), et vous obtiendrez cela:
AClass = function () {
// 
var maFn = function () { trace("Fn 2");};
};


donc, j'insiste, sur le coup j'ai cru a un bug, mais non, la c'est bon car flash fait une différence (et c'est bien normal) entre une déclaration de variable :
var maVar
//
maVar
//
maFn
//
maClass

et une :déclaration de function (et il en existe une seule):
function maFn () {
}


Conclusion de ma petite affaire
écrire
maClass  = function(){
}

ou
maFn = function(){
}

Ce n'est pas déclarer une fonction mais bien faire un passage par référence d'une fonction dans une variable... il est "équivalent" écrire :
maFn =null;
function refFn (){
}
maFn = refFn;

Donc dans le cas deux, écrire:
AClass = function () {
// 
maFn = function () {
trace("private function of AClass but public function by ref of maFn");
}
 maFn = refFn;
};
oObj = new AClass();
maFn();

équivaut a écrire
AClass = function () {
// 
maFn = "une variable sur le _root";
function refFn() {
trace("private function of AClass but public function by ref of maFn");
}
 maFn = refFn;
};
oObj = new AClass();
maFn();


Bon, c'est clair pour moi, mais suis pas sur de l,avoir écrit aussi clairement pour vous ;)

Je vais regarder les implications sur le cas d'adressage de function dans les namespace (création de package a la moock.org) org.moock.maClass (ou maFn, c'est pareil) = function (){}

Ca pourrait poser en fait un certains problèmes... (d'ailleurs c'est ptete pour ca que les dvpeurs de macromedia, dans leurs composant ne font pas de namespace, ils mettent tout sur le _root ou sur le _global... je vais réfléchir sur la question, ce serait une bien embêtante bien cette affaire là...
0
cs_nasian Messages postés 3 Date d'inscription lundi 25 août 2003 Statut Membre Dernière intervention 26 juillet 2004
26 juil. 2004 à 18:07
Suite et fin des "comprotements étranges"

je viens de tomber "enfin" sur une explication concrete expliquant pourquoi un classe disparu ne detruit pas necessairement ses methodes et ce n'est pas rien !

http://www.kirupa.com/developer/oop/AS1OOPInheritance7.htm

Bilan des courses, pour détruire un objet instancié, mieux vaut faire une destruction de ces methodes et attributs et ensuite détruire l'objet luyi-meme.

J'ai pas testé mais cela devrait donner qqchose du genre :

   for (var i in path.monObjet) {   
       path.monObjet[i] = null   
       delete path.monObjet[i];   
   }
   path.monObjet = null;   
   delete path.monObjet;   


//
path: est le chemin qui mene à l'objet désigné.
0
Rejoignez-nous