关于event对象中的currentTarget属性有时候为null这件事

关于event对象中的currentTarget属性有时候为null这件事

前景提要

event.currentTarget
MDN只说明了它表示事件的当前目标,总是指向事件绑定的元素。让我们来看下示例一:

<!-- HTML -->
<div id="outer">
  <div id="inner"></div>
</div>
/* CSS */
#outer {
  width: 100px;
  height: 100px;
  background-color: lightpink;
}

#inner {
  width: 50px;
  height: 50px;
  background-color: lightyellow;
}
//JavaScript
document.getElementById('outer').addEventListener('click', function(event) {
  console.log('event.currentTarget:', event.currentTarget);
  console.log('event.target:', event.target);
  console.log('this:', this);//注意:若事件处理程序为箭头函数,则this指向window(not strict)或为undefined('use strict')
});

点击inner,打印结果一切正常,不再赘述:

event.currentTarget: <div id="outer">​…​</div>​
event.target: <div id="inner"></div>this: <div id="outer">​…​</div>

问题复现

实际上,currentTarget这个属性是一个实时值而不是快照,随着事件冒泡阶段的结束,它将被解引用,这就是它为null的原因。也就是说如果我们在事件处理程序中使用异步代码访问该属性,就会发生这个问题。让我们来看下示例二(从此省略HTML、CSS):

document.getElementById('outer').addEventListener('click', function(event) {
  setTimeout(() => {console.log('event.currentTarget:', event.currentTarget)}, 0);
  setTimeout(() => {console.log('event.target:', event.target)}, 0);
  setTimeout(() => {console.log('this:', this)}, 0);
});

点击inner,打印结果如下:

event.currentTarget: null
event.target: <div id="inner"></div>this: <div id="outer">​…​</div>

注意到:就算排期为0的宏任务也会发生这个问题,文末将会演示微任务的情况。

解决方案

既然知道了问题原因,那么对症下药,在同步代码中保存该属性的指针,然后再在异步代码中调用。让我们来看下示例三:

document.getElementById('outer').addEventListener('click', function(event) {
  setTimeout(() => {console.log('event.currentTarget:', event.currentTarget)}, 0);
  const ct = event.currentTarget;
  setTimeout(() => {console.log('ct:', ct)}, 0);
});

点击inner,打印结果如下:

event.currentTarget: null
ct: <div id="outer">​…​</div>

拓展探究

在“问题复现”中我们知道,该属性在排期为0的宏任务中都会发生解引用问题,微任务呢?让我们来看下示例四:

document.getElementById('outer').addEventListener('click', function(event) {
  Promise.resolve(event.currentTarget).then(console.log);
});

点击inner,打印结果如下:

<div id="outer">​…​</div>

可以发现:在立即解决的期约回调中,该属性不会被解引用,这与宏任务的结果不一致。
但这不代表微任务不会发生解引用,在比较耗时的期约回调中调用该属性仍然会得到null,可以再参考下面的示例:

闲得蛋疼

document.getElementById('outer').addEventListener('click', function(event) {
  new Promise(resolve => setTimeout(() => resolve(event.currentTarget), 0)).then(console.log);
});
  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值