Differenza tra knockout Visualizza i modelli dichiarati come letterali degli oggetti rispetto alle funzioni


195

In knockout js vedo View Models dichiarate come:

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

ko.applyBindings(viewModel );

o:

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

ko.applyBindings(new viewModel ());

Qual è la differenza tra i due, se presente?

Ho trovato questa discussione sul gruppo google knockoutjs ma non mi ha dato una risposta soddisfacente.

Vedo un motivo se volevo inizializzare il modello con alcuni dati, ad esempio:

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

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

Ma se non lo faccio, importa quale stile scelgo?


Non credo ci sia differenza. Di solito uso il modello di costruzione, poiché spesso ho metodi che preferisco dichiarare su prototype(metodi che spesso, ad esempio, recuperano i dati dal server e aggiornano di conseguenza il modello di vista). Tuttavia potresti ovviamente dichiararli come proprietà di un oggetto letterale, quindi non riesco davvero a vedere la differenza.
James Allardice,

4
Questo non ha nulla a che fare con knockout, e tutto a che fare con la facilità di
creazione

1
@Kev se viewModel è una funzione di costruzione, la scrivi in ​​UpperCase proprio come var PersonViewModel = function () {...};
Elisabeth,

Risposte:


252

Ci sono un paio di vantaggi nell'usare una funzione per definire il tuo modello di vista.

Il vantaggio principale è che hai accesso immediato a un valore thisuguale all'istanza che viene creata. Ciò significa che puoi fare:

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);
};

Quindi, il tuo osservabile calcolato può essere associato al valore appropriato di this, anche se chiamato da un ambito diverso.

Con un oggetto letterale, dovresti fare:

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

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

In tal caso, è possibile utilizzare viewModeldirettamente nell'osservabile calcolato, ma viene valutato immediatamente (per impostazione predefinita), quindi non è possibile definirlo all'interno dell'oggetto letterale, poiché viewModelnon è definito fino a quando l'oggetto letterale non viene chiuso. A molte persone non piace che la creazione del modello di visualizzazione non sia incapsulata in una chiamata.

Un altro modello che è possibile utilizzare per assicurarsi che thissia sempre appropriato è impostare una funzione nella funzione uguale al valore appropriato thise usarla invece. Questo sarebbe come:

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

Ora, se si rientra nell'ambito di un singolo articolo e si chiama $root.removeItem, il valore di thissarà effettivamente i dati vincolati a quel livello (che sarebbe l'elemento). Utilizzando self in questo caso, è possibile assicurarsi che venga rimosso dal modello di visualizzazione generale.

Un'altra opzione sta usando bind, che è supportata dai browser moderni e aggiunta da KO, se non è supportata. In tal caso, sembrerebbe:

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

C'è molto di più che si possa dire su questo argomento e molti modelli che è possibile esplorare (come modello di modulo e modello di modulo rivelatore), ma fondamentalmente l'uso di una funzione offre maggiore flessibilità e controllo su come viene creato l'oggetto e sulla capacità di riferimento variabili private per l'istanza.


1
Bella risposta. Uso spesso una funzione (usando un modello di modulo rivelatore) per oggetti complessi come i modelli. Ma per i modelli semplici, utilizzo una funzione in modo da poter gestire tutto in un unico posto.
John Papa,

1
@JohnPapa - ho appena visto il tuo video PluralSight su knockout (poco più della metà - e, per coincidenza, ho appena visto la sezione sulla funzione letterale vs dell'oggetto). Davvero ben fatto e ha contribuito a far cadere il centesimo. Vale la pena un abbonamento di un mese solo per quello.
Kev

@Kev - Grazie. Sono contento che ne stiate ricavando valore. Alcuni non si preoccuperanno di quel modulo in quanto non è in realtà un concetto Knockout, più di modelli JavaScript. Ma con Knockout ho scoperto che quei concetti mi hanno davvero aiutato a creare un codice più pulito e stabile. Comunque, sono contento che ti piaccia :)
John Papa

dovrebbe essere self.items = ko.observableArray (); nel tuo secondo esempio? Hai usato questo, è corretto?
JackNova,

1
@JackNova nella funzione di costruzione selfe thissono uguali, quindi entrambi saranno equivalenti. Nella funzione removeItem, selfdiventa più utile, poiché thisnon sarebbe più l'istanza corrente quando eseguita nel contesto di un elemento figlio.
RP Niemeyer,

12

Uso un metodo diverso, sebbene simile:

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

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

Coppia di motivi:

  1. Non usare this, il che può creare confusione quando utilizzato all'interno di ko.computeds ecc
  2. Il mio viewModel è un singleton, non ho bisogno di creare più istanze (ad es. new viewModel())

Questo sta rivelando il modello del modulo se non sbagliato. Buona risposta ma la domanda non riguardava questo modello.
Phil

@paul: mi dispiace chiedere il vecchio thread. My viewModel is a singleton, I don't need to create multiple instances (i.e. new viewModel()) hai detto, ma non è chiaro cosa I don't need to create multiple instances stai cercando di dire, potresti venire con un uso maggiore in modo da poter capire il vantaggio del tuo approccio. grazie
Mou,

IMO, uno dei motivi per cui dichiareresti ViewModel functionè perché lo eseguiresti più di una volta. Tuttavia, nel mio esempio, è una funzione anonima immediatamente richiamata, quindi non verrà creata più di una volta. È molto simile all'oggetto letterale nell'esempio sopra, ma ti dà più isolamento
paulslater19
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.