web-dev-qa-db-fra.com

Javascript: appel de méthodes d'objet dans cet objet

Quel est le meilleur modèle de conception pour réaliser ce qui suit (qui ne fonctionne pas)?

var obj = (function() {

  // code defining private variables and methods

  var _obj = {
    property: value,
    method1: function() {
      // do stuff
    },
    method2: function() {
      // use property
      var prop = _obj.property; // obviously doesn't work
      // call method1
      obj.method1(); // "obj" not finished being defined yet!
    }
  };

  // obviously now I could do...
  var prop = _obj.property;

  return _obj;

})();

// and I could now do...
obj.method1();

Une variante qui, je pense, devrait fonctionner est

var obj = (function() {

  var property = value,
      method1 = function() {
        // do stuff
      },
      method2 = function() {
        // use property
        var prop = property;
        // call method1
        method1();
      },
      _obj = {
        property: property,
        method1: method1,
        method2: method2
      };

  return _obj;

})();

De même, comment fonctionne-t-il pour les objets destinés à être créés avec l'opérateur new? Dans la fonction constructeur elle-même, vous pouvez écrire this.method(). Mais que se passe-t-il si vous voulez garder le constructeur petit, en ne définissant que les éléments qui seront probablement personnalisés lors de la création, puis en définissant le reste dans le prototype? (Cela semble être le modèle commun.) Les propriétés/méthodes du prototype peuvent-elles interagir de quelque manière que ce soit?

var MyObj = function(name) {
  this.name = name;
};

var obj = new MyObj('Bob');

MyObj.prototype = {
  called_often: function() {
    // lots more code than just the following
    return document.getElementById('someID').value;
  },

  global_default: 'value', // can be changed, so need to pull value when run

  does_stuff: function(value) {
    var str = global_default + value, // can't access global_default on its own
        input = MyObj.called_often(), // doesn't work; MyObj.prototype.called_often() DOES
        name = this.name; // 'this' used in the prototype doesn't work
                          // even within a created object
    return name + input + str;
  }
};

Je suis sûr qu'il existe de meilleures façons d'obtenir mon résultat chaque fois que je rencontre ce problème. Ce code n'est pas spécifique à la situation et illustre simplement le problème général. Vous ne pourrez donc pas me donner d'alternative aux situations spécifiques que je rencontre. Mais vous pouvez peut-être m'aider dans ma réflexion globale.

29
Marcus Hughes

Eh bien, à partir de votre premier exemple:

var _obj = {
    property: value,
    method1: function() {
      // do stuff
    },
    method2: function() {
      // use property
      var prop = this.property; 
      // call method1
      this.method1(); 
    }
  };

C'est à cela que sert la valeur this.

Maintenant, ce que vous ne pouvez pas faire, c'est faire référence à une propriété d'un objet "en construction" ailleurs dans la syntaxe littérale de l'objet. (Il est difficile de donner un exemple car ce n'est tout simplement pas possible du point de vue syntaxique.) Dans les cas où vous voulez le faire, vous avez besoin d'une ou plusieurs instructions d'affectation distinctes.

36
Pointy

Devine quoi? Vous compliquez des choses simples. La réponse de Pointy est bonne, mais la méthode du prototype est meilleure pour plusieurs raisons. C'est pourquoi je décris (plutôt que j'apporte des corrections) la dernière méthode. Vérifiez ce violon .

var MyObj = function(name) {
  this.name = name;
};

MyObj.prototype = {
  called_often: function() {
    // lots more code than just the following
    return 'VALUE'; //document.getElementById('someID').value;
  },

  global_default: 'value', // can be changed, so need to pull value when run

  does_stuff: function(value) {
    var str = this.global_default + value, // can't access global_default on its own
        input = this.called_often(), // doesn't work; MyObj.prototype.called_often() DOES
        name = this.name; // 'this' used in the prototype doesn't work
                          // even within a created object
    return name + input + str;
  }
};

var obj = new MyObj('Bob');
10
Parth Thakkar