web-dev-qa-db-fra.com

Différence entre les modèles d'affichage masqués déclarés en tant que littéraux d'objet par rapport à des fonctions

Dans knockout js, je vois View Models déclaré comme étant:

var viewModel = {
    firstname: ko.observable("Bob")
};

ko.applyBindings(viewModel );

ou:

var viewModel = function() {
    this.firstname= ko.observable("Bob");
};

ko.applyBindings(new viewModel ());

Quelle est la différence entre les deux, le cas échéant?

J'ai trouvé cette discussion sur le groupe google knockoutjs mais cela ne m'a pas vraiment donné de réponse satisfaisante.

Je peux voir une raison si je voulais initialiser le modèle avec des données, par exemple:

var viewModel = function(person) {
    this.firstname= ko.observable(person.firstname);
};

var person = ... ;
ko.applyBindings(new viewModel(person));

Mais si je ne le fais pas, le style que je choisis est-il important?

193
Kev

L'utilisation d'une fonction pour définir votre modèle de vue présente quelques avantages.

Le principal avantage est que vous avez un accès immédiat à une valeur de this égale à l'instance en cours de création. Cela signifie que vous pouvez faire:

var ViewModel = function(first, last) {
  this.first = ko.observable(first);
  this.last = ko.observable(last);
  this.full = ko.computed(function() {
     return this.first() + " " + this.last();
  }, this);
};

Ainsi, votre observable calculé peut être lié à la valeur appropriée de this, même si elle est appelée depuis une autre portée.

Avec un objet littéral, vous devriez faire:

var viewModel = {
   first: ko.observable("Bob"),
   last: ko.observable("Smith"),
};

viewModel.full = ko.computed(function() {
   return this.first() + " " + this.last();
}, viewModel);

Dans ce cas, vous pouvez utiliser viewModel directement dans l'observable calculé, mais celui-ci est évalué immédiatement (par défaut) et vous ne pouvez donc pas le définir dans l'objet littéral, car viewModel n'est pas défini. jusqu'à ce que l'objet littéral soit fermé. Beaucoup de gens n'aiment pas que la création de votre modèle d'affichage ne soit pas encapsulée dans un seul appel.

Un autre modèle que vous pouvez utiliser pour vous assurer que this est toujours approprié consiste à définir une variable dans la fonction égale à la valeur appropriée de this et à l'utiliser à la place. Ce serait comme:

var ViewModel = function() {
    var self = this;
    this.items = ko.observableArray();
    this.removeItem = function(item) {
         self.items.remove(item);
    }
};

Maintenant, si vous êtes dans la portée d'un élément individuel et appelez $root.removeItem, la valeur de this sera en réalité la donnée liée à ce niveau (qui serait l’élément). En utilisant self dans ce cas, vous pouvez vous assurer qu'il est supprimé du modèle de vue globale.

Une autre option consiste à utiliser bind, qui est pris en charge par les navigateurs modernes et ajouté par KO, s'il n'est pas pris en charge. Dans ce cas, cela ressemblerait à:

var ViewModel = function() {
    this.items = ko.observableArray();
    this.removeItem = function(item) {
         this.items.remove(item);
    }.bind(this);
};

Il y a beaucoup plus à dire sur ce sujet et de nombreux modèles à explorer (tels que le modèle de module et le modèle de module révélant), mais l'utilisation d'une fonction vous donne plus de flexibilité et de contrôle sur la manière dont l'objet est créé et la possibilité de faire référence à les variables qui sont privées à l'instance.

251
RP Niemeyer

J'utilise une méthode différente, bien que similaire:

var viewModel = (function () {
  var obj = {};
  obj.myVariable = ko.observable();
  obj.myComputed = ko.computed(function () { return "hello" + obj.myVariable() });

  ko.applyBindings(obj);
  return obj;
})();

Couple de raisons:

  1. Ne pas utiliser this, ce qui peut créer de la confusion lorsqu'il est utilisé dans ko.computed S etc.
  2. Mon viewModel est un singleton, je n'ai pas besoin de créer plusieurs instances (c'est-à-dire new viewModel())
12
paulslater19