2013-01-25 8 views
21

ja backbone.js uczenia się i czują się zagubieni w tej sprawie: śledzę tutorialu: http://arturadib.com/hello-backbonejs/Kiedy należy użyć _.bindAll() w Backbone.js?

jak widać w pierwszym przykładzie (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); 

Ale jeśli skomentuję zdanie: _.bindAll(this, 'render');, to nadal będzie działać. Mam wyszukiwane w google i ktoś powiedział, że metoda bindAll() jest konieczne, ponieważ jeśli zmieniłem kontekst, wywołanie this.render może być niedostępne. Czuję się zagubiony w "kontekście". a może ktoś mógłby mi wyjaśnić, kiedy wywołanie (this.render) będzie niedostępne?

Odpowiedz

26

Na przykład dałeś _.bindAll(this, 'render'); nie jest konieczne, ale jeśli masz zwrotnych funkcji gdzie this może być ewentualnie zmieniona na kontekście czegoś innego, wtedy _bindAll() może być przydatna.

Na przykład:

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

wszystko w wydarzeniach jest automatycznie wiązane przez szkielet, FYI. –

+0

bardzo ładne wyjaśnienie, świetna robota – M3ghana

2

w tym przypadku nie trzeba się _.bindAll, ale powiedzmy, że twój pogląd mieć metodę, która powoduje rerender i zrobić coś takiego:

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

jeśli nie masz _.bindAll dla render Twój kontekst byłby wyłączony.

10
  • Wszelkie metody wymienione jako wartości nieruchomości w imprezach Państwa zdanie jest hash są automatycznie zobowiązane do Ciebie przez kręgosłup
  • Wszelkie metody w widoku, który ręcznie używają jako obsługi zdarzeń z modeli lub kolekcji należy ręcznie związany przez bindAll
    • lub można zapewnić kontekst podczas rejestracji wiązania
    • lub można użyć EMCA 5 na function.bind aby uzyskać taki sam efekt

urywek:

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 wystarczy użyć coffeescript i strzały tłuszczu i rozwiązać ten problem czysto na poziomie języka.

+2

Lubię więcej _.bindAll (this) również, ale Underscore nie poleca tego i nie będzie już wspierane od wersji 1.5.0. W dzienniku zmian można przeczytać: Usunięto możliwość wywoływania _.bindAll bez argumentów nazwy metody. Dosyć mądrzej jest wymieniać białe nazwy metod, które chcesz powiązać. http://underscorejs.org/#changelog Myślę, że to błąd. O wiele trudniej będzie mi to utrzymać. – ccsakuweb

+0

@ ccsakuweb Obecnie pracuję nad interfejsem internetowym, w którym intensywnie używam szkieletu. W tym projekcie mam obecnie dokładnie * jeden * call do '_.bindAll', a żaden do' _.bind'. Zamiast tego używam 'this.listenTo' do słuchania zdarzeń modelu,' 'wydarzeń' dla zdarzeń DOM itp., I zamiast tego dostarczam kontekst w ten sposób. Jedno wywołanie '_.bindAll' jest dla metody' run' działającej w tle autorefreshera, która wywołuje 'setTimeout (this.run, period)', co powoduje, że metoda 'run' traci swój kontekst. Cała reszta do tej pory była doskonale zarządzalna bez '_.bindAll'. –

2

Weźmy się bliżej co _.bindAll robi z underscore.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; 
    }; 

To, co robi się, to automatyczne powiązanie wszystkich funkcji do właściwego kontekstu. (Gdzie jego funkcja jest zadeklarowana zamiast powoływać.

Osobiście uważam, że to konwencja o starej wersji backbone.js związać swoje events lub słuchaczy akcji DOM. Ponieważ nowe wersje Backbone View automatycznie wiązać i rozpiąć słuchaczy w events .Znajdź więcej, szukaj Binding "this"here

Mam nadzieję, że pomoże.

Powiązane problemy