Class methods as event handlers in JavaScript?

前端 未结 4 1095
予麋鹿
予麋鹿 2020-11-29 00:59

Is there a best-practice or common way in JavaScript to have class members as event handlers?

Consider the following simple example:


            


        
相关标签:
4条回答
  • 2020-11-29 01:41
    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 almost 10 years later, with ES6, arrow functions and class properties

    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

    0 讨论(0)
  • 2020-11-29 01:46

    A function attached directly to the onclick property will have the execution context's this property pointing at the element.

    When you need to an element event to run against a specific instance of an object (a la a delegate in .NET) then you'll need a closure:-

    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'))
    
    0 讨论(0)
  • 2020-11-29 01:49

    You can use fat-arrow syntax, which binds to the lexical scope of the function

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

    After that you can try

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

    You can try it on babel or if your browser supports ES6 on jsFiddle.

    Unfortunately the ES6 Class -syntax does not seem to allow creating function lexically binded to this. I personally think it might as well do that. EDIT: There seems to be experimental ES7 feature to allow it.

    0 讨论(0)
  • 2020-11-29 02:01

    I don't know why Function.prototype.bind wasn't mentioned here yet. So I'll just leave this here ;)

    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');
        }
    }
    
    0 讨论(0)
提交回复
热议问题