如果按特定顺序调用,则回调中的"this"通过apply绑定为未定义 [英] 'this' in callback bound as closure via apply becoming undefined if called in specific order

查看:47
本文介绍了如果按特定顺序调用,则回调中的"this"通过apply绑定为未定义的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个JS函数,我尝试在其中使用 this ,这应该是单击触发该函数的按钮:

I have a JS function where I try to use this which is supposed to be the button clicked to trigger the function:

function myAction( greeting ) { console.log( greeting + ", the button is :" + this ); this.remove(); }

然后我的页面上有几个按钮,比方说两个(实际上甚至只有页面上的两个按钮;我已经对其进行了测试):

I then have several buttons on my page, let's say two (this really even happens with only two buttons on the page; I've tested it):

<button id="button-one" class="click-me">Click Me</button>
<button id="button-two" class="click-me">Click Me</button>

根据我的经验,当我想使用事件侦听器回调时,需要将相关元素用作 this 以及其他函数参数;如果我们有几个按钮共享,例如同一个类;达到此目的的最佳方法是将该回调绑定为闭包(将迭代的元素捕获为 this + apply(传递有关的 this 元素):

From my experience, when I want to use event listener callbacks which require the use of the concerned element as this plus other function arguments; if we have several buttons sharing for example the same class; the best way to reach this is to bind that callback as a closure (to capture the iterated element as this + apply (to deliver the concerned this element):

var myButtons = document.getElementsByClassName( "click-me" );
var amountOfButtons = myButtons.length;
for ( var i = 0; i < amountOfButtons; i++ ) {
    myButtons[i].addEventListener( "click", (
      function(i) {
        return function() { myAction.apply( myButtons[i], ["hello"] ); };
      }(i))
    );
  }

我从来没有对这种方法有任何疑问;它总是有效的.真的是错误的方法吗?

I never had any problem with this approach; it always worked. Is it actually the wrong approach?

因为,现在我要面对的是,当我单击#button-one ,然后单击#button-two this实际上在严格模式下变为未定义,而窗口在非严格模式下变为;在第二次点击.相反,当我这样做时, this 始终保持为相应单击的按钮.它似乎以某种方式更新了 myButtons 集合,这样当通过第一次调用将第一个按钮删除时, 1 索引在该集合中变得不可用,因为仅剩一个按钮;另一个被删除.至少那是我的理论.但是在类似的代码案例中,我从未遇到过这个问题吗?那我该如何编码我想发生的事情?

Because, what I'm facing now is that, when I click on #button-one, and then click on #button-two, this actually becomes undefined in strict mode and the window in non-strict mode; on the second click. When I do it the other way around, this always sticks to be the accordingly clicked button. It somehow seems to update the myButtons collection, such that when the first button gets removed via the first call, the 1 index becomes unavailable in the collection, as there's only one remaining button; the other one being removed. At least that's my theory. But I've never faced this issue before in similar code cases? How shall I code what I want to happen then?

编辑

谢谢大家;还要特别感谢@Nenad Vracar,因为他的解决方案只需更改以下内容,就可以实现所需的最低限度的编辑,而这些编辑完全可以正常工作:

Thanks to all of you; and special thanks to @Nenad Vracar, as his solution led to the minimum needed edits which perfectly work, by simply changing:

var myButtons = document.getElementsByClassName( "click-me" );
var amountOfButtons = myButtons.length;
for ( var i = 0; i < amountOfButtons; i++ ) {
    myButtons[i].addEventListener( "click", (
      function(i) {
        return function() { myAction.apply( myButtons[i], ["hello"] ); };
      }(i))
    );
  }

收件人:

var myButtons = document.getElementsByClassName( "click-me" );
var amountOfButtons = myButtons.length;
for ( var i = 0; i < amountOfButtons; i++ ) {
    myButtons[i].addEventListener( "click", function() {
      myAction.apply( this, ["hello"] );
    });
  }

一个简单的智能解决方案,我从字面上看不到树木的木头!再次感谢!

Simple smart solution, I could literally not see the wood for the trees! thanks again!

注意.事件委托在这里并不是真正的选择,因为页面的DOM结构/需要附件的元素有些复杂,我通常更喜欢将函数附加到需要它的元素上.另外,我更喜欢不要将函数的代码更改为闭包本身,也不要更改函数的代码本身.因此,我决定使用此解决方案的原因.

Note. Event delegation was not really an option here, as the DOM structure of the page / the elements needing the attachment is somewhat complicated, and I generally prefer to attach the function to the elements needing it. Also, I prefer to not change the code of the function to be a closure itself, to not make changes to the function code itself. Hence the reason why I've decided to use this solution.

推荐答案

在使用 querySelectorAll 然后可以在其上使用 forEach 循环时,可以使用稍微不同的方法.在点击事件处理程序内,您不需要多余的闭包,而在 myAction 内部的 this 将是点击事件处理程序内的 this 您将它作为 thisArg 参数传递给 apply .

You could use slightly different approach where you use querySelectorAll and then you can use forEach loop on that. And inside the click event handler you don't need that extra closure and this inside the myAction will be the this inside the click event handler since you passed it as thisArg parameter to apply.

function myAction(greeting) {
  console.log(greeting + ", the button is :" + this.textContent);
  this.remove();
}

document
  .querySelectorAll(".click-me")
  .forEach(function(btn) {
    btn.addEventListener('click', function() {
      myAction.apply(this, ['Hello'])
    })
  })

<button id="button-one" class="click-me">One</button>
<button id="button-two" class="click-me">Two</button>

这篇关于如果按特定顺序调用,则回调中的"this"通过apply绑定为未定义的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆