Chiusure Javascript e ‘questo’

Ho un problema con un object che ho creato che assomiglia a qualcosa del genere:

var myObject = { AddChildRowEvents: function(row, p2) { if(document.attachEvent) { row.attachEvent('onclick', function(){this.DoSomething();}); } else { row.addEventListener('click', function(){this.DoSomething();}, false); } }, DoSomething: function() { this.SomethingElse(); //<-- Error here, object 'this' does not support this method. } } 

Il problema è che quando sono dentro la funzione ‘DoSomething’, ‘questo’ non si riferisce a ‘myObject’ cosa sto facendo male?

Quando viene chiamata la funzione, “questo” si riferisce alla riga. Se vuoi avere l’object, puoi farlo qualcosa come questo:]

 AddChildRowEvents: function(row, p2) { var theObj = this; if(document.attachEvent) { row.attachEvent('onclick', function(){theObj.DoSomething();}); } else { row.addEventListener('click', function(){theObj.DoSomething();}, false); } }, 

Quando viene chiamata la funzione, ha accesso alla variabile theOBj che era nello scope quando la funzione è stata definita.

this si riferisce sempre alla funzione interna, se hai funzioni annidate, devi creare un’altra variabile e puntare a this .

 var myObject = { AddChildRowEvents: function(row, p2) { var that = this; if(document.attachEvent) { row.attachEvent('onclick', function(){that.DoSomething();}); } else { row.addEventListener('click', function(){that.DoSomething();}, false); } } } 

Questo è un problema comune con le chiusure. Per risolverlo, prova qualcosa del genere:

 var myObject = { AddChildRowEvents: function(row, p2) { var self = this; if(document.attachEvent) { row.attachEvent('onclick', function(){this.DoSomething(self);}); } else { row.addEventListener('click', function(){this.DoSomething(self);}, false); } }, DoSomething: function(self) { self.SomethingElse(); } } 

Il problema con il tuo codice è qui, nella seguente riga di codice hai definito una funzione anonima e l’hai passata come gestore di eventi per l’evento onClick, nelle seguenti righe:

  row.attachEvent('onclick', function(){this.DoSomething();}); 

e

  row.addEventListener('click', function(){this.DoSomething();}, false); 

quando l’evento onclick viene generato e chiama la funzione anonima che hai passato, questo contesto si riferisce all’object che è stato generato l’evento, ma non a myObject . perché a questo punto il contesto di esecuzione è nel contesto del gestore di eventi.

La soluzione: puoi fare il trucco che è stato detto a Mike Kantor, o usare jQuery, usare il metodo proxy, per definire questo contesto nella funzione anonima.

Quindi il tuo codice sarebbe come questo:

 var myObject = { AddChildRowEvents: function(row, p2) { if(document.attachEvent) { row.attachEvent('onclick', $.proxy(function () { this.DoSomething(); }, this)); } else { row.addEventListener('click', $.proxy(function () { this.DoSomething(); },this), false); } }, DoSomething: function() { this.SomethingElse(); //<-- Error here, object 'this' does not support this method. } } 

hai accennato che l'errore si trova in questo.SomthingElse () , ma il tuo codice non lo mostra. Se ottieni veramente errori su quella riga di codice, potresti utilizzare il metodo DoSomthing da qualche altra parte come gestore di eventi.

Il problema deriva dal modo in cui this viene gestito in JS, che può essere veloce, specialmente quando si chiama callback in modo asincrono (e quando viene creata una chiusura, associata a questo).

Quando viene chiamato il metodo AddChildRowEvents, this riferimento bene alla variabile myObject . Ma lo scopo di questo metodo è quello di mettere un gestore per fare clic. Quindi l’evento verrà triggersto qualche volta in futuro. A quel tempo, quale object attiverà davvero l’evento? In effetti, è l’ DOM element su cui l’utente farà clic. Quindi this farà riferimento a questo DOM element e non alla variabile myObject .

Per una soluzione più moderna di quelle presentate, è ansible utilizzare il bind method o la arrow function .

1. Soluzione con funzione freccia

 let handler = { addEventHandler: function(row) { console.log("this", this) row.addEventListener("click", () => { console.log("this", this) this.doSomethingElse() }) }, doSomethingElse: function() { console.log("something else") } } var div = document.querySelector("div") handler.addEventHandler(div) 
 
one