在 javascript 原型事件处理程序中保留“this”引用

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8100469/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-26 02:16:45  来源:igfitidea点击:

Preserve 'this' reference in javascript prototype event handler

javascriptoopevent-handlingthis

提问by George Hess

What is the correct way to preserve a thisjavascript reference in an event handler stored inside the object's prototype? I'd like to stay away from creating temp vars like '_this' or 'that' and I can't use a framework like jQuery. I saw a lot of people talk about using a 'bind' function but was unsure of how to implement it in my given scenario.

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

回答by Tomasz Nurkiewicz

I find bind()being the cleanest solution so far:

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

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

BTW the otherthisis called thatby convention very often.

顺便说一句,另一个经常被惯例this称为that

回答by Chris Baker

Check out the MDN document on bind: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind

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

Using this functionality, you can change the scope (what thisis):

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

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

Be aware, however, that this is a new addition to EMCA and thus may not be supported in all user agents. There is a pollyfill available at the MDN document linked above.

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

回答by Paolo Moretti

The problem with bindis that is only supported by IE9+.

问题bind只有 IE9+ 支持

The function can be polyfilled with es5-shim, but it's not completely identical to the native implementation:

该函数可以用 填充es5-shim,但它与本机实现并不完全相同:

  • Caveat: the bound function has a prototype property.
  • Caveat: bound functions do not try too hard to keep you from manipulating their argumentsand callerproperties.
  • Caveat: bound functions don't have checks in calland applyto avoid executing as a constructor.
  • 警告:绑定函数有一个原型属性。
  • 警告:绑定函数不要太努力阻止你操纵它们的argumentscaller属性。
  • 警告:绑定函数没有签入callapply避免作为构造函数执行。


Another alternative can be jQuery.proxy:

另一种选择可以是jQuery.proxy

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

This is even more helpful if you want to remove the event handler later, because when a function goes through the proxymethod, jQuery generates a new guid value and then applies that guid to both the core function as well as the resultant proxy function, so that you can use the original function reference to unbind an event handler callback that has been proxied:

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

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

回答by Alexandre Germain

Other solution: use the "arrow functions" introduced by ES6. Those have the particularity to not change the context, IE what thispoints to. Here is an example:

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

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

箭头函数规范@MDN

Edit

编辑

Be carefull with it. If you use it client-side and you can't be sure of the capabilities of the JS interpreter, note that old browser won't recognize arrow functions (see CanIUse stats). Use this method only if you KNOW what will run it (recent browsers only & NodeJS apps)

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