2010-06-21 14 views
5

// codice della classe base minified (se è necessario il codice non compresso, lo posterò) function Class() {} Class.prototype.construct = function() {}; Class.extend = function (c) { var a = function() {argomenti [0]! == Classe & & this.construct.apply (this, arguments)}, d = nuovo this (Class), f = this.prototype; for (var e in c) {var b = c [e]; if (b instanceof Function) b. $ = f; d [e] = b} a.prototype = d; a.extend = this.extend; return a};Come trovo l'istanza a cui appartiene un metodo?

// custom event class 
var Event = Class.extend({ 
    handlers: [], 
    // stores the event handler 
    subscribe: function(handler, thisObj) { 
     this.handlers.push([handler, thisObj]); 
    }, 
    // calls the event handlers 
    fire: function() { 
     for(i in this.handlers) { 
      var handler = this.handlers[i]; 
      handler[0].apply(handler[1]); 
     } 
    } 
}); 
var Class2 = Class.extend({ 
    myEvent: new Event(), // the event 
    test: function() { // fires the event 
     this.myEvent.fire(this); 
    } 
}); 
var Class3 = Class.extend({ 
    construct: function(model) { 
     this.name = "abc"; 
     model.myEvent.subscribe(this.handler, this); // subscribe to the event 
    }, 
    handler: function() { 
     alert(this.name); // alerts 'abc' 
    } 
}); 
var instance1 = new Class2(); 
var instance2 = new Class3(instance1); 
instance1.test(); 

L'unico modo per rendere il codice gestore di eventi per lavorare con il bene 'questo' è con l'aggiunta di un nuovo argomento ('thisObj') per il metodo 'iscriversi'? C'è un modo migliore per farlo?

risposta

2

Il comportamento che si ottiene è dovuto al fatto che quando si passa un "metodo" a una funzione, la funzione di ricezione non ha idea che sia un metodo. È solo un blocco di javascript che deve essere eseguito.

Prototipo ottiene intorno a questo problema con il metodo di bind

È possibile ottenere un comportamento simile (non ho guardato i dettagli di implementazione di bind) utilizzando una chiusura.

var Class3 = Class.extend({ 
    construct: function(model) { 
     this.name = "abc"; 
     //model.myEvent.subscribe(this.handler, this); // subscribe to the event 
     var self = this; 
     model.myEvent.subscribe(function() {self.handler()}); 
    }, 
    handler: function() { 
     alert(this.name); // alerts 'abc' 
    } 
}); 

o applicare alcune funzionalità simile al metodo sottoscrizione della classe Event personalizzata.

MODIFICATO Per riflettere le osservazioni di CMS. Grazie!

+0

Quando eseguo questo codice in Firefox ottengo: self.handler non è una funzione .. Leggerò di più su queste chiusure .. e guarderò all'implementazione di Prototype di bind .. jQuery ha anche $ .proxy che penso fa la stessa cosa, ma sto lavorando su un piccolo progetto che dovrebbe essere indipendente da qualsiasi libreria JavaScript. Comunque grazie! – silviubogan

+2

Una funzione anonima che viene eseguita immediatamente, avrà sempre il valore 'this' che punta all'oggetto globale, ad esempio' (function() {return this === window;})(); // true', non hai bisogno di quella funzione, devi solo assegnare 'var self = this;' nella funzione di inclusione (costrutto) e usare una semplice funzione anonima (come quella che si restituisce) per eseguire 'self .handler(); '. – CMS

+0

Non conoscevo la prima parte della funzione anonima che aveva "questo" riferimento all'oggetto globale. Buono a sapersi. Grazie! –

Problemi correlati