【问题标题】:Preserve 'this' reference in javascript prototype event handler [duplicate]在javascript原型事件处理程序中保留“this”引用[重复]
【发布时间】:2016-04-17 01:52:36
【问题描述】:

在对象原型中存储的事件处理程序中保留this javascript 引用的正确方法是什么?我想远离创建像'_this'或'that'这样的临时变量,我不能使用像jQuery这样的框架。我看到很多人谈论使用“绑定”功能,但不确定如何在我的给定场景中实现它。

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

【问题讨论】:

    标签: javascript oop event-handling this


    【解决方案1】:

    我发现bind() 是迄今为止最干净的解决方案:

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

    顺便说一句,other this 按照惯例经常被称为 that

    【讨论】:

    • 讨厌创建一个名为“that”的引用(a la Crockford)。我更喜欢“实例”(la Stefanov)或“我”(la ExtJS)
    • 实际上,我讨厌创建this 引用,无论它们如何命名。但请同意,that 并不是最好的命名方式。
    • 我使用“self”,但最近发现这是与 WebWorkers 中顶级属性的名称冲突。并不是说你不能有相同的名字,但它确实使事情变得混乱。另外,我发现“那个”这个名字与“这个”完全相反
    • @GeorgeJempty 这只是个人喜好
    • 这当然不适用于旧 IE(8 及更早版本)
    【解决方案2】:

    查看bind上的MDN文档:https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind

    使用此功能,您可以更改范围(this 是什么):

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

    但是请注意,这是 EMCA 的新增功能,因此可能并非所有用户代理都支持。上面链接的 MDN 文档中有一个 pollyfill 可用。

    【讨论】:

      【解决方案3】:

      bind 的问题在于only supported by IE9+

      该函数可以用es5-shim进行polyfill,但与原生实现并不完全相同:

      • 警告:绑定函数具有原型属性。
      • 警告:绑定函数不要试图阻止您操纵它们的 argumentscaller 属性。
      • 警告:绑定函数在 callapply 中没有检查,以避免作为构造函数执行。

      另一种选择可以是jQuery.proxy

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

      如果您想稍后删除事件处理程序,这会更有帮助,因为当函数通过proxy 方法时,jQuery 会生成一个新的 guid 值,然后将该 guid 应用于核心函数以及生成的代理函数,以便您可以使用原始函数引用来取消绑定已代理的事件处理程序回调:

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

      【讨论】:

      • .bind() 不亚于$.proxy 完全跨浏览器。它基本上是.bind() 的非标准版本。如果您列出的警告实际上是一个问题,那么$.proxy 不会更好。更何况问题很明确,他不能用jQuery。
      • @squint 我建议使用$.proxy(或类似的实现),因为它是一个松散的连接,这在 OO 事件处理中非常有用。但是谢谢你,我会更新我的答案,因为就像你说的那样,填充的 .bind()$.proxy 一样完全跨浏览器。
      【解决方案4】:

      其他解决方案:使用 ES6 引入的“箭头函数”。那些具有不改变上下文的特殊性,即this指向的IE。这是一个例子:

      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

      编辑

      小心点。如果您在客户端使用它并且无法确定 JS 解释器的功能,请注意旧浏览器无法识别箭头函数 (see CanIUse stats)。仅当您知道什么会运行它时才使用此方法(仅限最近的浏览器和 NodeJS 应用程序)

      【讨论】:

        猜你喜欢
        • 2011-01-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-09-18
        • 1970-01-01
        • 2013-07-13
        • 1970-01-01
        相关资源
        最近更新 更多