2014-10-04 18 views
9

Entrambi i blocchi di codice sotto funzionano, nel contesto e sembrano completamente equivalenti dal punto di vista funzionale. Capisco ragionevolmente lo js prototypes, quindi non sto chiedendo loro di per sé (a meno che lo sia l' l'unica differenza).viewmodel .prototype .function vs self .function in viewmodel?

Piuttosto, confrontando due modi semplici per mettere un metodo su un modello di vista come illustrato di seguito, ci sono implicazioni/differenze per Knockout, ad esempio tempo vincolante?

define ([ "knockout", "testo ./ home.html!"], La funzione (ko, homeTemplate) {// < - Un AMD Module

function HomeViewModel(route) { 
      var self = this; 
      self.message = ko.observable('Snacks!'); 

      self.eatSomething = function() { 
        self.message('Yum, a viewmodel snack.'); 
      }; 
    } 
    return { viewModel: HomeViewModel, template: homeTemplate }; 
}); 

contro l'aggiunta di metodo via prototipo:

define ([ "knockout", "! testo ./ home.html"], la funzione (ko, homeTemplate) {

function HomeViewModel(route) { 
      this.message = ko.observable('Snacks!'); 
    }; 

    HomeViewModel.prototype.eatSomething = function() { 
      this.message('Yum, the same viewmodel snack, only different?'); 
    }; 
    return { viewModel: HomeViewModel, template: homeTemplate }; 

});

(il codice è un semplice mod di Yeoman's uscita ponteggio tramite un Knockout generator. Ha creato il codice piastra di caldaia per un knockout component, abbastanza recente (KO 3.2) e caratteristica molto gradita. Un bel componente explainer KO è here.)

risposta

11

Nel primo esempio, dal momento che la funzione utilizza self (che è impostato ad un riferimento alla nuova istanza) anziché this, non importa quanto la funzione viene chiamata/vincolato, sarebbe sempre correttamente fissare il proprio message osservabile .

Nel secondo esempio, quando si associa normalmente alla funzione come data-bind="click: eatSomething", si ottiene lo stesso risultato. Knockout chiama la funzione con il valore di this uguale ai dati correnti.

Se si dispone di uno scenario in cui è necessario chiamare la funzione da un contesto diverso (forse il modello di vista ha un oggetto figlio che si sta utilizzando with o un modello contro). allora potresti usare un'associazione come data-bind="click: $parent.eatSomething". KO chiamerebbe comunque la funzione con this uguale ai dati correnti (che non sarebbe $parent), quindi avresti un problema.

Un vantaggio di mettere la funzione sul prototipo, però, è che se si è creato molti casi di HomeViewModel avrebbero tutti condividono la stessa eatSomething funzione tramite il loro prototipo, piuttosto che ogni istanza di ottenere la propria copia della funzione eatSomething. Questo potrebbe non essere un problema nel tuo scenario, poiché potresti avere solo uno HomeViewModel.

È possibile verificare che il contesto sia corretto chiamandolo come: data-bind="click: $parent.eatSomething.bind($parent). Utilizzando questa chiamata, creerebbe una nuova funzione wrapper che chiama l'originale con il contesto appropriato (valore di this). In alternativa, è possibile associarlo anche al modello di visualizzazione per mantenere pulito il rilegatore. In entrambi i casi, si perde parte del valore di metterlo sul prototipo, poiché si creano comunque le funzioni wrapper per ogni istanza. Il "coraggio" della funzione esisterebbe solo una volta sul prototipo, comunque almeno.

Tendo ad utilizzare i prototipi nel mio codice, ma non c'è dubbio che l'utilizzo della tecnica self (o qualcosa del tipo del modello di modulo rivelatore) può ridurre la preoccupazione per il valore di this.

+0

Chiarimento utile: cosa intendi per ** 'il modello del modulo rivelatore' **? A proposito, mi sono appena imbattuto in [Knockout AMD Helpers] (https://github.com/rniemeyer/knockout-amd-helpers) - sembra estremamente utile, specialmente come i moduli contenenti i propri modelli. Quindi grazie anche per quello! –

+0

Ci sono alcuni link che descrivono il modello del modulo rivelatore, eccone uno: http://weblogs.asp.net/dwahlin/techniques-strategies-and-patterns-for-structuring-javascript-code-revealing-module- modello. Fondamentalmente, definisci i metodi che vuoi internamente e sei in grado di fare riferimento direttamente alle variabili. Quindi, si restituisce l'API pubblica dal modulo con i metodi che si desidera esporre con qualsiasi nome con cui si desidera esporli. Spero possa aiutare! –

+1

@RPNiemeyer - non hai scritto un blog su questa domanda esatta? Ho pensato di ricordare di averlo letto in passato e di aver fatto ricerche su Google e questo è il posto dove sono finito – user210757