2013-01-25 15 views
21

sto backbone.js imparando, e si sentono confusi su questo: Seguo il tutorial: http://arturadib.com/hello-backbonejs/Quando è necessario utilizzare _.bindAll() in Backbone.js?

come si può vedere nel primo esempio (1.js):

(function($){ 
    var ListView = Backbone.View.extend({  
    el: $('body'), // attaches `this.el` to an existing element. 

    initialize: function(){ 
     _.bindAll(this, 'render'); // fixes loss of context for 'this' within methods 

     this.render(); // not all views are self-rendering. This one is. 
    }, 

    render: function(){ 
     $(this.el).append("<ul> <li>hello world</li> </ul>"); 
    } 
    }); 

    var listView = new ListView();  
})(jQuery); 

Ma se commento la frase: _.bindAll(this, 'render');, funzionerà ancora. Ho cercato su google e qualcuno ha detto che il metodo bindAll() è necessario poiché se ho cambiato il mio contesto, la chiamata di this.render potrebbe non essere disponibile. Mi sento confuso sul "contesto". e anche qualcuno potrebbe spiegarmi quando la chiamata (this.render) non sarà disponibile?

risposta

26

Per l'esempio che hai dato _.bindAll(this, 'render'); non è necessario, ma se si hanno le funzioni di callback dove this può eventualmente essere modificati per il contesto di qualcos'altro, allora _bindAll() può essere a portata di mano.

Per esempio:

initialize: function(){ 
    _.bindAll(this, 'render', 'clickFunc'); 
}, 
events: { 
    'click .someElement': 'clickFunc' 
}, 
clickFunc: function(e) { 
    /** If you remove the clickFunc from the list of events in bindAll, 
      'this' will refer to the element that invoked the event. 

     Adding the clickFunc event in the _.bindAll, ensures that 'this' stays 
      as the view. 
    */ 
    this /** <-- our focal point */ 
} 
+9

qualsiasi cosa negli eventi è legata automaticamente da backbone, FYI. –

+0

spiegazione molto bella, ottimo lavoro – M3ghana

2

in questo caso non è necessario il _.bindAll, ma diciamo la visualizzazione dispone di un metodo che provoca una nuovamente sottoposti a rendering e si fa qualcosa di simile:

.., 
myMethod: function() { 
    this.$('.someselector').change(this.render); 
}, 

se non si dispone di _.bindAll per render , il tuo contesto sarebbe fuori.

10
  • Tutti i metodi elencati come valori di proprietà negli eventi della vostra vista hash sono vincolati automaticamente per voi da spina dorsale
  • Tutti i metodi nella vista che si utilizza manualmente come gestori di eventi dai modelli o raccolte devono essere vincolati manualmente tramite bindAll
    • oppure si può fornire un contesto in cui si registra il legame
    • oppure è possibile utilizzare EMCA 5 di function.bind per ottenere lo stesso risultato

frammento:

events: { 
    'click .win': 'win', 
    'click .lose': 'lose' 
}, 
initialize: function() { 
    //win and lose are automatically bound for you 
    //because they are in the events property 

    //refresh must be manually bound 
    this.model.on('change', this.refresh); 

    //which you can do ECMA5 style if you like 
    this.model.on('change', this.refresh.bind(this)); 

    //OR you can provide a context backbone style 
    this.model.on('change:foo', this.fooChange, this); 

    //However, since you pretty much never want an unbound function 
    //in a view, you can just stick this in all your initialize methods 
    //and call it done 
    //Note this will bind all functions in your view class if you don't 
    //pass specific method names. I recommend this form. 
    _.bindAll(this); 
}, 
win: function() {...}, 
lose: function() {...}, 
refresh: function() {...}, 
fooChange: function() {...} 

... OOOOORRRR basta usare CoffeeScript e frecce grassi e risolvere questo in modo pulito a livello di lingua.

+2

mi piace di più _.bindAll (questo) anche, ma di sottolineatura non lo consiglio, e non saranno supportate tutte le versioni più dato 1.5.0. Nel registro delle modifiche è possibile leggere: Rimossa la possibilità di chiamare _.bindAll senza argomenti del nome del metodo. È quasi sempre più saggio elencare in bianco i nomi dei metodi che desideri associare. http://underscorejs.org/#changelog Penso che sia un errore. Mi sarà molto più difficile da mantenere. – ccsakuweb

+0

@ccsakuweb Attualmente sto lavorando su un'interfaccia web in cui utilizzo pesantemente Backbone. In questo progetto attualmente ho esattamente * una * chiamata a '_.bindAll', e none a' _.bind'. Invece io uso 'this.listenTo' per ascoltare gli eventi del modello, l'hash' events' per eventi DOM ecc. E fornire il contesto in questo modo. L'unica chiamata '_.bindAll' è per il metodo' run' di uno sfondo autorefresher, che chiama 'setTimeout (this.run, period)' che fa sì che il metodo 'run' perda il suo contesto. Tutto il resto a questo punto è stato perfettamente gestibile senza '_.bindAll'. –

2

consente di dare uno sguardo da vicino a ciò che fa da _.bindAllunderscore.js offical docs.

_.bindAll = function(obj) { 
    var i, length = arguments.length, key; 
    if (length <= 1) throw new Error('bindAll must be passed function names'); 
    for (i = 1; i < length; i++) { 
     key = arguments[i]; 
     obj[key] = _.bind(obj[key], obj); 
    } 
    return obj; 
    }; 

Quello che fa è associare automaticamente tutte le sue funzioni al contesto corretto. (Dove la sua funzione è dichiarata piuttosto che invocato.

io personalmente credo che fosse una convenzione per la vecchia versione di Backbone.js di legare le sue events, o gli ascoltatori di azione DOM. Dal momento che le nuove versioni Backbone View legano automaticamente e gli ascoltatori unbind in events .Trova più dalla ricerca Binding "this"here

spero che aiuta.

Problemi correlati