2011-06-06 12 views
7

tengo un caso que utiliza herencia de vistas, y mi código es esencialmente como:backbone.js ver herencia. `This` resolución de los padres

parentView = Backbone.View.extend({ 
    events: { 
     "some event": "business" 
    }, 
    initialize: function(){ 
     _.bindAll(this); 
    }, 
    business: function(e){ 
     ... 
     this.someFunc && this.someFunc(); 
     ... 
    } 
}); 

childView = parentView.extend({ 
    events: { 
     ... 
    }, 
    constructor: function(){ 
     this.events = _.extend({}, parentView.prototype.events, this.events); 
     parentView.prototype.initialize.apply(this); 
    }, 
    initialize: function(){ 
     _.bindAll(this); 
    }, 
    someFunc: function(){ 
     ... 
    } 
}); 

Actualización: Movido this.events extensión al constructor.

Mi vista hija tiene someFunc y, durante alguna función comercial en la vista principal, debe llamar a esa función si existe. Si this está configurado correctamente en childView, entonces debería existir this.someFunc. Esto, sin embargo, no es el comportamiento que estoy experimentando.

Durante la función initialize (en el elemento principal), this está configurado de hecho en la vista secundaria. Sin embargo, cuando se activa some event, se llama a la función business con this establecido en parentView.

Respuesta

9

¿Ha intentado extender this.events en el constructor, en lugar de en la función de inicialización? Si haces esto al inicializar, ya es demasiado tarde; la delegación de eventos para la función business ya se ha configurado en el constructor y apuntará a parentView (vea la llamada al this.delegateEvents(); en el constructor de Backbone.View).

actualizado con un ejemplo de trabajo:

ParentView = Backbone.View.extend({ 
    name: 'ParentView', 
    events: { 
     "event": "business" 
    }, 
    business: function(e){ 
     this.someFunc && this.someFunc(); 
    } 
}); 

ChildView = ParentView.extend({ 
    name: 'ChildView', 
    events: { 
    }, 
    constructor: function(){ 
     this.events = _.extend({}, ParentView.prototype.events, this.events); 
     console.debug(this.events); 
     ParentView.prototype.constructor.apply(this, arguments); 
    }, 
    someFunc: function(){ 
     console.debug('someFunc; this.name=%s', this.name); 
    } 
}); 

child = new ChildView(); 
$(child.el).trigger('event'); 
// logs 'this' in 'someFunc'; the name is 'ChildView'. 
+0

Bien, genial. ¿Puede decirme la diferencia entre parentView.prototype.initialize y parentView.constructor.initialize? – idbentley

+0

He actualizado mi pregunta: existe el mismo problema, incluso usando esta técnica. 'parentView.constructor.initialize' no está definido. – idbentley

+0

También he intentado: 'parentView.prototype.constructor', sin suerte. – idbentley

0

Puede resolver este problema mediante la adición de esta línea al método initialize del niño:

_.bind(this.business, this) 

Esperemos que alguien puede apuntar a una mejor descripción de los mecanismos subyacentes de lo que puedo dar, pero voy a dar Es una oportunidad:

Lo que ocurre es que el método utilizará el contexto del ámbito en el que se definió a menos que se indique lo contrario. initialize se le indica que use el contexto del niño cuando llame al parentView.prototype.initialize.apply(this) porque está pasando en el childView con la referencia this al método apply.

Puede vincular el método comercial al contexto del elemento secundario utilizando el método underscore.js bind como se describe anteriormente.

+0

derecho, pero eso es también lo que hace la función '_.bindAll'. Al usarlo sin ningún parámetro adicional, debe vincularse a todas las funciones en el objeto. Desafortunadamente, esto tampoco funciona. – idbentley

+0

oh, cierto, entendí, tienes razón. No estoy seguro :( – c3rin

2

En realidad, no sé si esto resuelve tu caso, pero generalmente hago esto: this.constructor.__super__.initialize.apply(this, arguments); y funciona como un amuleto. Mi solución es completamente incorrecta. He aquí por qué:

var Model1 = Backbone.Model.extend({ 
    method: function() { 
    // does somehting cool with `this` 
    } 
}); 

var Model2 = Model1.extend({ 
    method: function() { 
    this.constructor.__super__.method.call(this); 
    } 
}); 

var Model3 = Model2.extend({ 
    method: function() { 
    this.constructor.__super__.method.call(this); 
    } 
}); 

var tester = new Model3(); 

// Boom! Say hallo to my little stack-overflowing recursive __super__ call! 
tester.method(); 

La llamada a this.constructor.__super__ en Model2::method resolverá a (redoble de tambor) Model2::method.

Siempre use ExplicitClassName.__super__.methodName.call(this, arg1, arg2 /*...*/) o Coffee-script's super.

+0

Me gusta usar __super__ en lugar de hardcoding nombre de clase padre –

Cuestiones relacionadas