Domanda

Esiste un metodo best practice o comune in JavaScript per avere membri della classe come gestori di eventi?

Considera il seguente esempio semplice:

<head>
    <script language="javascript" type="text/javascript">

        ClickCounter = function(buttonId) {
            this._clickCount = 0;
            document.getElementById(buttonId).onclick = this.buttonClicked;
        }

        ClickCounter.prototype = {
            buttonClicked: function() {
                this._clickCount++;
                alert('the button was clicked ' + this._clickCount + ' times');
            }
        }

    </script>
</head>
<body>
    <input type="button" id="btn1" value="Click me" />
    <script language="javascript" type="text/javascript">
        var btn1counter = new ClickCounter('btn1');
    </script>
</body>

Il gestore di eventi buttonClicked viene chiamato, ma il membro _clickCount è inaccessibile, oppure questo punta a qualche altro oggetto.

Qualche suggerimento / articolo / risorsa su questo tipo di problemi?

È stato utile?

Soluzione

ClickCounter = function(buttonId) {
    this._clickCount = 0;
    var that = this;
    document.getElementById(buttonId).onclick = function(){ that.buttonClicked() };
}

ClickCounter.prototype = {
    buttonClicked: function() {
        this._clickCount++;
        alert('the button was clicked ' + this._clickCount + ' times');
    }
}

EDIT quasi 10 anni dopo, con ES6, funzioni freccia e proprietà della classe

class ClickCounter  {
   count = 0;
   constructor( buttonId ){
      document.getElementById(buttonId)
          .addEventListener( "click", this.buttonClicked );
  }
   buttonClicked = e => {
     this.count += 1;
     console.log(`clicked ${this.count} times`);
   }
}

https://codepen.io/anon/pen/zaYvqq

Altri suggerimenti

Una funzione collegata direttamente alla proprietà onclick avrà la proprietà this del contesto di esecuzione che punta all'elemento.

Quando devi eseguire un evento element per eseguire un'istanza specifica di un oggetto (come un delegato alla .NET in .NET) allora avrai bisogno di una chiusura: -

function MyClass() {this.count = 0;}
MyClass.prototype.onclickHandler = function(target)
{
   // use target when you need values from the object that had the handler attached
   this.count++;
}
MyClass.prototype.attachOnclick = function(elem)
{
    var self = this;
    elem.onclick = function() {self.onclickHandler(this); }
    elem = null; //prevents memleak
}

var o = new MyClass();
o.attachOnclick(document.getElementById('divThing'))

Non so perché Function.prototype.bind non sia stato ancora menzionato qui. Quindi lascerò questo qui;)

ClickCounter = function(buttonId) {
    this._clickCount = 0;
    document.getElementById(buttonId).onclick = this.buttonClicked.bind(this);
}

ClickCounter.prototype = {
    buttonClicked: function() {
        this._clickCount++;
        alert('the button was clicked ' + this._clickCount + ' times');
    }
}

Puoi usare la sintassi fat-arrow, che si lega all'ambito lessicale della funzione

function doIt() {
  this.f = () => {
    console.log("f called ok");
    this.g();
  }
  this.g = () => {
    console.log("g called ok");
  }
}

Successivamente puoi provare

var n = new doIt();
setTimeout(n.f,1000);

Puoi provarlo su babel o se il tuo browser supporta ES6 su JsFiddle .

Sfortunatamente la sintassi della classe ES6 non sembra consentire la creazione di funzioni legate in modo lessicale a questo. Personalmente penso che potrebbe anche farlo. EDIT: sembra che ci sia funzionalità sperimentale ES7 per consentirlo .

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top