2012-03-06 3 views
185

En knockout js veo Visualización de modelos declarados como sea:Diferencia entre nocaut Visualización de modelos declarada como literales de objetos vs funciones

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

ko.applyBindings(viewModel); 

o:

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

ko.applyBindings(new viewModel()); 

¿Cuál es la diferencia entre los dos, en su caso ?

Encontré this discussion en el grupo de google knockoutjs pero en realidad no me dio una respuesta satisfactoria.

puedo ver una razón si quería para inicializar el modelo con algunos datos, por ejemplo:

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

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

Pero si yo no estoy haciendo eso qué importa qué estilo elegir?

+0

No creo que haya una diferencia. Usualmente uso el patrón de constructor, ya que a menudo tengo métodos que prefiero declarar en el 'prototipo' (métodos que a menudo, por ejemplo, captan datos del servidor y actualizan el modelo de vista en consecuencia). Sin embargo, todavía podría declararlos como propiedad de un objeto literal, por lo que realmente no puedo ver la diferencia. –

+4

Esto no tiene nada que ver con knockout, y todo tiene que ver con facilidad de instanciación de objetos personalizados en JavaScript – zzzzBov

+1

@Kev si el viewModel es una función constructora, se escribe en UpperCase como var PersonViewModel = function() {...} ; – Elisabeth

Respuesta

242

Hay un par de ventajas al usar una función para definir su modelo de vista.

La principal ventaja es que tiene acceso inmediato a un valor de this que es igual a la instancia que se está creando. Esto significa que usted puede hacer:

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

lo tanto, su observables computarizada se puede unir al valor apropiado de this, incluso si llama desde un ámbito diferente.

Con un objeto literal, que tendría que hacer:

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

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

En ese caso, se puede usar viewModel directamente en la observables computarizada, pero se vuelve evaluado inmediata (por defecto) por lo que no podía defínalo en el literal del objeto, ya que viewModel no está definido hasta después de que se cierra el literal del objeto. A muchas personas no les gusta que la creación de su modelo de vista no esté encapsulada en una sola llamada.

Otro patrón que puede utilizar para asegurarse de que this sea siempre apropiado es establecer una variable en la función igual al valor apropiado de this y usarlo en su lugar. Esto sería como:

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

Ahora, si usted está en el alcance de un elemento individual y llamar $root.removeItem, el valor de this serán realmente los datos que se están ligados a ese nivel (lo que sería el elemento). Al usar self en este caso, puede asegurarse de que se elimine del modelo de vista general.

Otra opción es usar bind, que es compatible con navegadores modernos y agregado por KO, si no es compatible. En ese caso, se vería como:

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

hay mucho más que se puede decir sobre este tema y muchos patrones que se puede explorar (como patrón de módulo y el diseño del módulo revelador), pero básicamente usando una función da tiene más flexibilidad y control sobre cómo se crea el objeto y la capacidad de referenciar variables que son privadas para la instancia.

+1

Gran respuesta. A menudo uso una función (usando un patrón revelador de módulo) para objetos complejos como viewmodels. Pero para los modelos simples, utilizo una función para que pueda manejar todo en un solo lugar. –

+1

@JohnPapa: acabo de ver tu video PluralSight en un golpe de gracia (justo por encima de la mitad y, casualmente, acabo de ver la sección sobre el objeto literal frente a la función). Realmente bien hecho y ha ayudado a que caiga el centavo. Vale la pena un mes de suscripción solo por eso. – Kev

+0

@Kev - Gracias. Me alegra que estés obteniendo valor de esto. A algunos no les importará ese módulo, ya que no es realmente un concepto de Knockout, sino más bien patrones de JavaScript. Pero descubrí, a medida que avanzaba con Knockout, que esos conceptos realmente me ayudaron a crear un código más estable y más limpio. De todos modos, me alegro de que lo disfrutes :) –

12

Puedo usar un método diferente, aunque similar:

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

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

par de razones:

  1. No usar this, que puede confusión cuando se utiliza dentro de ko.computed s etc
  2. Mi modelo de vista es una singleton, no es necesario crear varias instancias (es decir, new viewModel())
+0

Este es un modelo de módulo revelador si no se confunde. Buena respuesta, pero la pregunta no era sobre este patrón. – Phil

+0

@paul: Perdón por pedir un hilo viejo. dijiste 'My viewModel es un singleton, no necesito crear varias instancias (es decir, new viewModel())' pero no está claro lo que estás tratando de decir 'No necesito crear varias instancias' puedes comprar vienen con más uso para que uno pueda entender la ventaja de su enfoque. gracias – Mou

+0

IMO, una de las razones por las que declararía ViewModel como 'función' es porque lo ejecutaría más de una vez. Sin embargo, en mi ejemplo, es una función anónima invocada de inmediato, por lo que no se creará más de una vez. Es muy similar al Object Literal en el ejemplo anterior, pero te da más aislamiento – paulslater19

Cuestiones relacionadas