【问题标题】:Class methods as event handlers in JavaScript?类方法作为 JavaScript 中的事件处理程序?
【发布时间】:2008-10-23 09:21:47
【问题描述】:

在 JavaScript 中是否有最佳实践或常用方法将类成员用作事件处理程序?

考虑以下简单示例:

<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>

事件处理程序 buttonClicked 被调用,但 _clickCount 成员不可访问,或者 this 指向其他对象。

关于这类问题的任何好的提示/文章/资源?

【问题讨论】:

    标签: javascript html function class


    【解决方案1】:
    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');
        }
    }
    

    几乎 10 年后编辑,使用 ES6、箭头函数和 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

    【讨论】:

    • 感谢您的解决方案。我也试图了解更大的图景——模式、实践等。你知道任何好的文章吗?
    • 这是一个很好的例子,但是对于这里的新手来说,这个答案可能会更好地解释为什么它是一个很好的解决方案。
    • ES2015 编辑通过 Babel 工作,但所有浏览器都不允许使用公共字段语法(即使现在是 2019 年)。
    • 在我的应用程序中不太有效。底层类是由一个工厂构建的,它也设置了事件监听器。事件触发时的“this”变量就是工厂的变量。试图弄清楚 addEventListener 如何知道在调用事件处理程序时要使用什么 'this' ..
    • 将处理程序方法从 clicked(){ ...} 更改为 clicked = () => {...} 并且它可以工作。因为我收集的匿名函数使用“this”的方式不同?
    【解决方案2】:

    我不知道为什么这里还没有提到Function.prototype.bind。所以我就把它留在这里;)

    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');
        }
    }
    

    【讨论】:

    • 确实干净简单的解决方案! +1
    • 这不起作用。 “this.buttonClicked 未定义”
    • @FabioDelarias 它应该可以工作,请查看示例。 codepen.io/anon/pen/QzwRKE?editors=1010
    • 很好的解决方案,可能是它实际应该完成的方式。
    【解决方案3】:

    直接附加到 onclick 属性的函数将使执行上下文的 this 属性指向元素。

    当你需要一个元素事件来针对一个对象的特定实例(在 .NET 中的一个委托)运行时,你需要一个闭包:-

    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'))
    

    【讨论】:

      【解决方案4】:

      您可以使用胖箭头语法,它绑定到函数的词法范围

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

      之后你可以试试

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

      您可以在 babel 上试用,或者如果您的浏览器支持 ES6,请在 jsFiddle 上试用。

      不幸的是,ES6 Class -syntax 似乎不允许创建词法绑定到 this 的函数。我个人认为它也可以这样做。编辑:似乎有experimental ES7 feature to allow it

      【讨论】:

        【解决方案5】:

        我喜欢使用unnamed 函数,只是实现了一个可以正确处理此问题的导航类:

        this.navToggle.addEventListener('click', () => this.toggleNav() );
        

        那么this.toggleNav()可以只是Class中的一个函数。

        我知道我曾经调用过命名函数,但它可以是您在两者之间放入的任何代码,如下所示:

        this.navToggle.addEventListener('click', () => { [any code] } );
        

        因为arrow 你传递了这个实例并且可以在那里使用它。

        Pawel 有一点不同的约定,但我认为使用 functions 更好,因为其中的 ClassesMethods 的命名约定是要走的路:-)

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2018-10-06
          • 2023-04-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-06-26
          • 1970-01-01
          相关资源
          最近更新 更多