2011-11-11 15 views
17

Qual è il modo corretto di conservare un riferimento javascript this in un gestore di eventi memorizzato all'interno del prototipo dell'oggetto? Mi piacerebbe stare lontano dalla creazione di vars temporanei come '_questo' o 'quello' e non posso usare un framework come jQuery. Ho visto molte persone parlare dell'uso di una funzione "bind", ma non ero sicuro di come implementarlo nel mio scenario.Mantieni 'questo' riferimento nel gestore di eventi prototipo javascript

var Example = function(foo,bar){ 
    this.foo = foo; 
    this.bar = bar; 
}; 
Example.prototype.SetEvent = function(){ 
    this.bar.onclick = this.ClickEvent; 
}; 
Example.prototype.ClickEvent = function(){ 
    console.log(this.foo); // logs undefined because 'this' is really 'this.bar' 
}; 

risposta

20

trovo bind() essere la soluzione più pulita finora:

this.bar.onclick = this.ClickEvent.bind(this); 

BTW l'altrothis è chiamato that per convenzione molto spesso.

+3

I * odio * creando un riferimento a questo chiamato "that" (a la Crockford). Preferisco "instance" (a la Stefanov) o "me" (a la ExtJS) –

+4

In realtà, odio creare riferimenti "this", non importa come vengono chiamati. Ma d'accordo, questo non è il miglior nome. –

+1

Io uso 'self', ma ho trovato solo di recente che si tratta di un conflitto di nomi con una proprietà di primo livello in WebWorkers. Non che tu non possa avere lo stesso nome, ma confonde le cose. Inoltre, trovo che il nome 'that' sia esattamente l'opposto di 'this' – Matt

7

estrarre il documento MDN su bind: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind

Utilizzando questa funzionalità, è possibile modificare l'ambito (quello this è):

Example.prototype.SetEvent = function(){ 
    this.bar.onclick = this.ClickEvent.bind(this); 
}; 

essere consapevoli, tuttavia, che si tratta di una nuova aggiunta in EMCA e quindi potrebbe non essere supportato in tutti i programmi utente. È disponibile un pollyfill nel documento MDN collegato sopra.

3

Il problema con bind corrisponde a only supported by IE9+.

La funzione può essere polyfilled con es5-shim, ma non è del tutto identica a quella implementazione nativa:

  • Caveat: la funzione limite ha una proprietà prototipo.
  • Avvertenza: le funzioni associate non sono troppo difficili per impedirti di manipolare le loro proprietà arguments e caller.
  • Avvertenza: le funzioni associate non dispongono di controlli in call e apply per evitare l'esecuzione come costruttore.

Un'altra alternativa può essere jQuery.proxy:

$(elem).on('click', $.proxy(eventHandler, this)); 

Questo è ancora più utile se si desidera rimuovere il gestore di eventi più tardi, perché quando una funzione passa attraverso il metodo proxy, jQuery genera un nuovo valore guida e quindi applica quel guid sia alla funzione core sia alla funzione proxy risultante, in modo che sia possibile utilizzare il riferimento alla funzione originale per separare un callback del gestore eventi che è stato proxy:

$(elem).off('click', eventHandler); 
+0

'.bind () 'non è meno completamente cross-browser di' $ .proxy'. È fondamentalmente una versione non standard di '.bind()'. Se gli avvertimenti che hai elencato sono in realtà una preoccupazione, allora '$ .proxy' non andrà meglio. Per non parlare del fatto che la domanda è chiara sul fatto che non può usare jQuery. –

+0

@squint Suggerisco di usare '$ .proxy' (o un'implementazione simile) perché è una connessione allentata, ed è qualcosa di veramente utile nella gestione degli eventi di OO. Ma grazie aggiornerò la mia risposta perché, come stai dicendo, un 'polybilled' .bind() 'non è meno completamente cross-browser di' $ .proxy'. –

0

Altra soluzione: utilizzare le "funzioni freccia" introdotte da ES6. Quelli hanno la particolarità di non cambiare il contesto, cioè a cosa punta this.Ecco un esempio:

function Foo(){ 
    myeventemitter.addEventListener("mousedown", (()=>{ 
     return (event)=>{this.myinstancefunction(event)}; /* Return the arrow 
function (with the same this) that pass the event to the Foo prototype handler */ 
    })()); 
} 
Foo.prototype.myinstancefunction = function(event){ 
    // Handle event in the context of your Object 
} 

Arrow function specs @ MDN

Modifica

essere attento con esso. Se lo si utilizza lato client e non si è certi delle funzionalità dell'interprete JS, si noti che il vecchio browser non riconoscerà le funzioni di freccia (see CanIUse stats). Utilizzare questo metodo solo se SAPETE cosa lo eseguirà (solo browser recenti & app NodeJS)

Problemi correlati