Bonjour,

je suis en train de refaire la partie javascript de mon site perso et j'utilise pour cela les objets javascript afin de clarifier mon code et de séparer les différentes fonctionnalités (il y a aussi un partie apprentissage dans ce cas précis).
J'ai donc créé dans un premier temps un objet contenant des propriétés et des méthodes comme ceci :

obj1.init();

var obj1 = {
    property_1:  a,
    property_2: b,
    self: null,
    init: function() {
            self = this;
        // traitement
    },
    method_1: function(){
        // traitement
    },
    method_2: function() {
        // traitement
    }
}

Afin de pouvoir apperler les méthodes et/ou propriétés de mon object, j'ai défini une propriété self = this dans ma méthode init().
Lorsque j'initialise l'object avec la méthode init() au démarrage de l'application, tout fonctionne correctement.

Par contre, si je crée un deuxième objet, contenant lui aussi la propriété self = this dans la fonction init() de l'objet 2, la propriété self de l'objet 1 est égale à l'objet 2 :

// initialisation des objets
obj1.init();
obj2.init();

// définition des objets
var obj2 = {
    property_1:  a,
    property_2: b,
    self: null,
    init: function() {
        self = this;
        // traitement
    },
    method_1: function(){
        // traitement
    },
    method_2: function() {
        // traitement
    }
}
var obj1 = {
    property_1:  a,
    property_2: b,
    self: null,
    init: function() {
            self = this;
        // traitement
    },
    method_1: function(){
        // traitement
        console.log(self); // retourne obj2
    },
}

Ce comportement se retrouve lorsque j'utilise la variable self dans une fonction liée à un eventListener. D'après la doc, la variable this qui en découle devient l'objet window d'où ma propention à utiliser la variable self afin de récupérer les propriétés de mon objet.
Par contre, ce que je ne comprends pas, c'est pourquoi, en définissant une variable propre à un objet, celle-ci se retrouve à avoir les propriétés d'un autre objet !

Théoriquement, les deux variables self définies au sein de chaque objet devraient se référer à l'objet en question et non pas à un autre objet ? Est-ce que je loupe quelque chose ou est-ce un comportement "normal" du javascript ? Comment pourrais-je faire pour contourner ce problème ?

Merci d'avance pour vos réponse,
Romain

9 réponses


all-lala
Réponse acceptée

Alorts le soucis est différent maintenant.
Tu remplace une fonction de par une autre fonction dans le callback de l'eventListener.

regarde ça :
http://jsbin.com/juqomakube/1/edit?html,console

La solution étant :

var obj1 = {
        init: function() {
            var that = this;
            window.addEventListener('click', function(){
              that.onClick()
            });
        },
        onClick: function(){
            console.log(this) // retourne l'objet en cours et non le window
        }
    }
    obj1.init();
Romano83
Auteur

Salut,
toujours pas d'idées quant à mon problème ?

Bonjour,

Dans ton cas self est une variable globale.
this.self ferai référence au self de ton objet en cours.
Regarde ça :

var self = "Ho Nooo";
var test = {
    self : "He si",

    init(){
        console.log(self); // variable self globale
        console.log(this.self); // parametre self de l'objet
    }
}
test.init()
console.log(self) // variable self globale

Si tu veu avoir un self dans une méthode tu devrais faire :

var self = "Ho Nooo";
var test = {
    self : "He si",

    init(){
        var self = this;
        console.log(self); // le self référence de l'objet en cours
        console.log(this.self); // parametre self de l'objet
    }
}
test.init()
console.log(self) // variable self globale

Salut,

Je pense que la meilleure chose à faire est que tu changes ta variable self par autre chose. "self" est un variable du navigateur, tu risques d'avoir des problèmes de scope surtout si c'est pour mettre this dedans, car self = windows. Je te laisse faire un test dans ta console, mais clairement c'est une très mauvaise pratique de renommer self même dans un objet. Tu peux l'appeler "_this" par exemple.

Romano83
Auteur

@galyb merci pour ta remarque. J'avais déjà essayé avec le self renomé en that dans les deux objets et j'avais tout de même ce problème .
@all-lala je vais voir ce que donne ta solution en renommant self en un autre nom de variable !

Ton soucis n'est pas un problème de nom de variable mais de porté (ou encapsulation).

Avec ta méthode :

var obj1 = {
    self: null,
    init: function() {
            self = this;
    }
}

Le self que tu définit n'est pas celui de l'objet obj1 mais une variable globale accessible partout.
tu peut même faire :

var obj1 = {
    self: null,
    init: function() {
            self = this;
    }
}
obj1.init()
console.log(self);

Ceci dans une console d'un navigateur moderne (chrome/firefox) pour te convaincre que self contient bien un objet qui contient un paramètre self à null.

{self: null, init: ƒ}

Suivant ce que tu veut faire il va faloir déclarer la variable au bon endroit pour quelle ai la boinne porté.
Si tu souhaite acceder a ton objet partout c'est déjà le cas avec ta déclaration d'objet.
Si tu souhaite acceder au dernier objet initié avec une variable ta méthode est la bonne.
Si tu souhaite acceder a ton objet dans une méthode de l'objet this est fait pour.
Si tu souhaite acceder a ton objet dans une fonction d'une méthode de ton objet (un callback par exemple) tu déclare un var that (ou self) = this et tu utlise that (ou self).

exemple : https://jsfiddle.net/4s666zq0/

Romano83
Auteur

Salut,
merci pour tes explications all-lala !

J'ai essayé d'appliquer ce que tu me dis mais j'ai encore queslques questions... J'ai vraiment du mal à appréhender l'histoire le l'encapsulation des variables...

Voici ce que j'ai fait pour tester :

var obj1 = {
    property1: null,
    property2 : null,
    init: function() {
        var that = this;
        that.property1 = "a";
        that.property2 = "b";
        window.addEventListener('click', that.onClick);
    },
    method_1: function() {
        console.log(this.property1) // retourne "a"
    }
    onClick: function() {
        console.log(this) // retourn l'objet window (comportement normal)
        // récupération de l'objet courant ?
    }
}

Le problème vient lorsque je souhaite accéder à une propriété de l'objet dans ma fonction onClick...
Le this fait référence à l'objet window, ce qui est le comportement normal de javascript... A part de faire quelque chose comme ceci :

var obj1 = {
    // ...
    onClick: function() {
        var that = this.obj1;
        // traitement
    }
}

Je ne vois pas trop comment faire autrement...

Romano83
Auteur

OK !
Merci beaucoup pour ta réponse, ça fonctionne !
Par contre, petite question pour ma culture : pourquoi quand tu fais comme ce que tu as marqué, le this retourne l'objet en cours et non le window... J'avoue ne pas comprendre cette subtilité...

En fait il fauit voir le remplacement des fonction de callback.
Quand tu a une fonction de ce type:

var test = function(){}

Si tu a un objet comme celui-ci :

var obj = {
    init: function(){
        var that = this; // inutile ici!
        test = that.newTest
    }
    newTest : function(){
        console.log(this);
    }
}

Ta function test équivaut à :

var test = function(){
        console.log(this);
    }

Et donc si tu execute test() tu lance la fonction console.log(this); avec this qui vaut window puisque c'est le parent global.

par contre si tu fait un objet comme celui-ci:

var obj = {
    init: function(){
        var that = this;
        test = function(){
            that.newTest()
        }
    }
    newTest : function(){
        console.log(this);
    }
}

Ta fonction test équivaut à :

var test = function(){
            that.newTest()
        }

Et that fait référence à l'objet déclaré avant cela.
Et donc si tu execute test() tu lance la fonction that.newTest() quiu dans son contexte lance console.log(this); avec this qui vaut l'objet déclaré.

Je sait pas si j'ai été clair, mais il faut principalement se poser la question de la function qui remplacera celle qui ets en place, généralement dans un callback tel que celui des eventlistner c'est vide et le contexte est celui de l'objet sur lequel tu place l'event.