IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

JavaScript Discussion :

[POO] "This" et son scope


Sujet :

JavaScript

  1. #1
    Membre éprouvé
    Profil pro
    Inscrit en
    Janvier 2009
    Messages
    201
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2009
    Messages : 201
    Par défaut [POO] "This" et son scope
    Bonjour à tous!

    J'ai une interrogation, lorsque je suis dans mon objet JS. "this" fait référence à ce même objet (jusque là rien de délirant?).

    Mais, si mon objet lance un CallBack, et que cette fonction CallBack est déclaré dans mon objet: que vaut this?

    Un exemple peut pour concrétiser tout ça:
    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
     
    var MyObject = function()
    {
       this.param = 'value';
       this.Init = function()
       {
           alert(this.param); // Affiche value.
       }
     
       AnObject.AddListener('click', this.OnClickCallBack};
       this.OnClickCallBack()
       {
           alert(this.param); // affiche undefined
       }
    }
    vous auriez une idée?

  2. #2
    Rédacteur/Modérateur

    Avatar de SpaceFrog
    Homme Profil pro
    Développeur Web Php Mysql Html Javascript CSS Apache - Intégrateur - Bidouilleur SharePoint
    Inscrit en
    Mars 2002
    Messages
    39 659
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 75
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Développeur Web Php Mysql Html Javascript CSS Apache - Intégrateur - Bidouilleur SharePoint
    Secteur : Industrie

    Informations forums :
    Inscription : Mars 2002
    Messages : 39 659
    Billets dans le blog
    1
    Par défaut
    AnObject.AddListener('click', this.OnClickCallBack};



    sinon essaye plutot avec cette syntaxe
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    AnObject.onclick=function(){this.OnclickCallBack();}
    Ma page Developpez - Mon Blog Developpez
    Président du CCMPTP (Comité Contre le Mot "Problème" dans les Titres de Posts)
    Deux règles du succès: 1) Ne communiquez jamais à quelqu'un tout votre savoir...
    Votre post est résolu ? Alors n'oubliez pas le Tag

    Venez sur le Chat de Développez !

  3. #3
    Membre éprouvé
    Profil pro
    Inscrit en
    Janvier 2009
    Messages
    201
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2009
    Messages : 201
    Par défaut
    Décidément je fais n'importe quoi quand je poste... un copier collé raté encore, il n'y a pas de soucis de syntaxe dons le code.

    Par contre je n'ai pas totalement la main sur l'objet envoyant le CallBack ,le code exact est:
    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
     
    var Gmaps = function(canva, address)
    {
        this.address = address;
        this.minimizedCanva = canva;
        this.map = null;
        this.Init = function()
        {
            this.map = new GMap2($(this.minimizedCanva));
     
            Gmaps_ClientGeocoder.getLocations(this.address, function(response)
            {
                this.map.clearOverlays(); // ici map n'existe pas, pourtant déclarer dans Gmaps.
                // ...
            });
        }
    Dans le CallBack de Gmaps_ClientGeocoder.getLocations, this fait référence a la méthode elle même (par exemple this.response existe, et renvoie le paramètres de la méthode).

    Mais comment pourrais-je avoir accès à l'instance de mon objet Gmaps?

  4. #4
    Membre très actif
    Inscrit en
    Janvier 2009
    Messages
    598
    Détails du profil
    Informations forums :
    Inscription : Janvier 2009
    Messages : 598
    Par défaut
    ça te sert à quoi le callback ? (je sais meme pas ce que c'est^^)

    Peut-etre qu'on peut faire plus simple pour ce que tu veux faire ?

  5. #5
    Membre éprouvé
    Profil pro
    Inscrit en
    Janvier 2009
    Messages
    201
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2009
    Messages : 201
    Par défaut
    Les callback sont utilisé pour des opération asynchrone. En javascript ça se traduit généralement par de l'ajax.

    Par exemple, je lance une requête vers une page quelconque. Le code javascript n'attend pas le retour. Il continue sont execution. Et pouf dès qu'il y a un retour, il exécute ton CallBack, qui est fait une méthode.


    Donc là, dans ce que je souhaite faire. Lorsque que la méthode Gmaps_ClientGeocoder.getLocations a abouti, elle execute ma function passé en paramètres (le deuxième paramètres pour tout simplement être le nom d'une méthode).

  6. #6
    Membre très actif
    Inscrit en
    Janvier 2009
    Messages
    598
    Détails du profil
    Informations forums :
    Inscription : Janvier 2009
    Messages : 598
    Par défaut
    Merci de l'info, mais pourquoi as-tu besoin d'apeler une méthode de ton objet de cette façon ? Ne peux-tu pas l'appeler de façon normale et directement ?
    (Normalement si)

  7. #7
    Membre éprouvé
    Profil pro
    Inscrit en
    Janvier 2009
    Messages
    201
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2009
    Messages : 201
    Par défaut
    Bien sur que je peux, mais ça n'aurais aucun intérêts

    Ce que je veux c'est Exécuter cette méthode lorsque Gmaps_ClientGeocoder.getLocations à décidé que c'était le bon moment (quand il a eu la réponse ajax en gros). Mais surtout cette méthode vas me passer un argument, qui est le résultats de son opération, et que donc, je ne possède pas.

  8. #8
    Membre très actif
    Inscrit en
    Janvier 2009
    Messages
    598
    Détails du profil
    Informations forums :
    Inscription : Janvier 2009
    Messages : 598
    Par défaut
    Ha ok, donc je ne peux pas t'aider malheureusement je ne me suis pas encore penché sur Ajaxia^^

    Sinon il n'y a pas une proprièté du style owner pour ce "this" qui reférence la méthode ?
    Sinon ce serait pratique : This.owner^^ qui donnerait le parent donc l'objet.

  9. #9
    Membre éprouvé
    Profil pro
    Inscrit en
    Janvier 2009
    Messages
    201
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2009
    Messages : 201
    Par défaut
    Bon je viens de trouver une solution (que je trouve horrible) à force de chercher et de debugger:
    Placer mon objet dans une variable locale...
    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
    this.Init = function()
    {
        this.map = new GMap2($(this.minimizedCanva));
        this.map.addControl(new GSmallMapControl());
        
        var $this = this;
        Gmaps_ClientGeocoder.getLocations(this.address, function(response)
        {
            $this.map.clearOverlays();
            if (!response || response.Status.code != G_GEO_SUCCESS)
            {
                alert(GMAPS_ERRORMESSAGE);
            }
            else
            {
                var place = response.Placemark[0];
                var point = new GLatLng(place.Point.coordinates[1], place.Point.coordinates[0]);
                var marker = new GMarker(point);
                
                $this.map.addOverlay(marker);
                $this.map.setCenter(point);
                $this.map.setZoom(15);
            }
        });
    }
    Si quelqu'un à une explication ou une meilleure solution je suis preneur!

  10. #10
    Membre expérimenté Avatar de marts
    Inscrit en
    Février 2008
    Messages
    233
    Détails du profil
    Informations forums :
    Inscription : Février 2008
    Messages : 233
    Par défaut
    Tu pourrais adjoindre à la fonction un pointeur vers l'objet que tu veux utiliser dedans :
    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
     
    this.Init = function()
    {
        this.map = new GMap2($(this.minimizedCanva));
        this.map.addControl(new GSmallMapControl());
     
        var callback=function(response)
        {
            var map=arguments.callee.targetMap;
            map.clearOverlays();
            if (!response || response.Status.code != G_GEO_SUCCESS)
            {
                alert(GMAPS_ERRORMESSAGE);
            }
            else
            {
                var place = response.Placemark[0];
                var point = new GLatLng(place.Point.coordinates[1], place.Point.coordinates[0]);
                var marker = new GMarker(point);
     
                map.addOverlay(marker);
                map.setCenter(point);
                map.setZoom(15);
            }
        }
        callback.targetMap=this.map;
     
        Gmaps_ClientGeocoder.getLocations(this.address, callback);
    }

  11. #11
    Rédacteur
    Avatar de marcha
    Homme Profil pro
    Développeur Web
    Inscrit en
    Décembre 2003
    Messages
    1 571
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : Suisse

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Décembre 2003
    Messages : 1 571
    Par défaut
    @DarkHerumor: Ce que tu as trouvé comme solution s'appelle une closure,
    ce n'est pas une solution horrible du tout, c'est très courant et très
    pratique, voir souvent indispensable.

    Mais pour répondre à ta question de fond sur le contexte de this dans une
    callback, c'est le contexte de l'appelant qui est utilisé et non de l'instance dans laquelle
    est définie la fonction callback.

    Une fonction callback étant une référence direct à une fonction, elle perd
    le lien avec son éventuelle instance. En javascript il est possible d'appeler
    des fonctions d'une "classe" dans le context d'instance d'une autre.

    Pour choisir explicitement le contexte pour this il faut appeler la fonction
    avec apply ou call

    Mais comme c'est pas toi (mais l'API google dans ce cas) qui appelle la
    fonction, tu ne peux pas échapper à une forme de closure si tu veux
    un context différent pour this.

    Voici ton exemple initial modifié:

    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
    <script type='text/javascript'>
     
    function bindCallback(context, callback) {
      return function() {
        return callback.apply(context, arguments);
      };
    }
     
    var MyObject = function()
    {
       this.param = 'value';
     
       this.Init = function()
       {
           alert(this.param); // Affiche value.
       }
     
       this.OnClickCallBack = function()
       {
           alert(this.param); // affiche undefined
       }
     
       window.onload = bindCallback(this, this.OnClickCallBack);
     
    }
     
    var i = new MyObject();
    i.Init();
    </script>
    Ici la fonction bindCallback retourne une fonction, c'est cette
    fonction interne qui sera assignée au gestionaire d'évènement.
    On crée ici une closure, c'est à dire que les paramètres
    'context' et 'callback' restent accessibles de l'intérieur de la
    fonction interne et sont propres à chaque appels à bindCallback.

    On utilise apply pour appeler la callback souhaitée et lui fixer le
    context 'this' désiré. On propage aussi les arguments (qu'aurait
    pu recevoir la fonction interne depuis son gestionnaire d'évènement)
    grace au tableau arguments.

    Une autre solution plus élégante consiste à étendre le
    prototype de l'objet Function avec une fonction pour ça.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    Function.prototype.bind = function(context) {
      var m = this; // référence l'instance de Function
      return function() {
        return m.apply(context, arguments);
      }
    }
    l'usage est très élégant, on corrige l'exemple ainsi:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    window.onload = this.OnClickCallBack.bind(this);
    Ou pour le cas courrant de callbacks anonymes:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    window.onload = function(event) { ... }.bind(this);

  12. #12
    Membre éprouvé
    Profil pro
    Inscrit en
    Janvier 2009
    Messages
    201
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2009
    Messages : 201
    Par défaut
    Salut,

    Merci beaucoup, j'ai appris énormément de choses d'un coup sur les mécanique du js

    J'avoue qu'étant habitué à programmer dans des langages comme les c#, les fonctionnement du Js me sont assez inconnues. Avec vos différentes méthodes j'ai largement de quoi faire ce que je veux

    Merci encore, sujet Résolu :]

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. onmouseover=&quot;Menu_HoverStatic(this)&quot; object expected
    Par cyrano_de_bergerac dans le forum ASP.NET
    Réponses: 0
    Dernier message: 01/10/2010, 16h01

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo