事件currentTarget在setTimeout

时间:2016-09-22 21:28:15

标签: javascript html

考虑:

let sel=document.getElementById('mys');

sel.onchange=function(e) {
  console.log(e.currentTarget===null); // false
  setTimeout(e => {
     console.log(e.currentTarget===null); // true
  }, 0, e);
 }
<select id="mys">
  <option value="volvo">Volvo</option>
  <option value="saab">Saab</option>
  <option value="mercedes">Mercedes</option>
  <option value="audi">Audi</option>
</select>

  • 为什么e.currentTarget会在超时后发生变化?是一个浏览器(铬)错误?

  • 如何将事件的确切克隆转移到超时功能?我尝试过简单的克隆,但currentTarget不可写,不能被删除..

4 个答案:

答案 0 :(得分:1)

退出事件处理程序后,

event.currentTarget和其他一些属性会发生变化。

在事件处理程序中执行上下文切换(setTimeout(... ,0);)很常见,似乎正确传递事件(包括currentTarget等)的唯一方法是将其克隆如下。

请注意,这只是“足够好”......克隆不完全是原始事件,而且它的上下文不同......例如,clone.stopPropogation()没有意义......

如果您需要在克隆删除!d.writable || !d.configurable || !d.enumerable ||

上更改currentTarget等

let sel=document.getElementById('mys');

function cloneEvent(e) {
	function ClonedEvent() {};
	let clone=new ClonedEvent();
	for (let p in e) {
		let d=Object.getOwnPropertyDescriptor(e, p);
		if (d && (!d.writable || !d.configurable || !d.enumerable || d.get || d.set)) {
			Object.defineProperty(clone, p, d);
		}
		else {
			clone[p] = e[p];
		}  
	}
	Object.setPrototypeOf(clone, e);
	return clone;
}

sel.onchange=function(e) {
	console.log(e.currentTarget);
	let clone=cloneEvent(e);
	setTimeout(e => {
		console.log(e.currentTarget);
	}, 0, clone);
}
<select id="mys">
  <option value="volvo">Volvo</option>
  <option value="saab">Saab</option>
  <option value="mercedes">Mercedes</option>
</select>

答案 1 :(得分:1)

Joseph Marikle's comment的启发,我找到了真正的原因:

DOM Standard § 2.9. Dispatching events描述了该算法,我将在这里部分复制它:

[…]
5. If target is not relatedTarget or target is event’s relatedTarget, then:
    […]
    9. While parent is non-null:
        […]
        8. Otherwise, set target to parent and then:
            […]
        9. If parent is non-null, then set parent to the result of invoking parent’s get the parent with event.
        […]
    […]
    12. Set event’s eventPhase attribute to CAPTURING_PHASE.
    […]
    14. For each tuple in event’s path, in reverse order:
        1. […] invoke […]
    15. For each tuple in event’s path, in order:
        1. If tuple’s target is non-null, then set event’s eventPhase attribute to AT_TARGET.
        2. Otherwise, set event’s eventPhase attribute to BUBBLING_PHASE.
        3. […] invoke […]
[…]
6. Set event’s eventPhase attribute to NONE.
7. Set event’s currentTarget attribute to null.
[…]

因此,在事件处理完所有阶段(捕获,at_target,冒泡)之后,currentTarget被分配了null

答案 2 :(得分:-1)

let sel=document.getElementById('mys');

sel.onchange=function({currentTarget}) {
  console.log(currentTarget===null); // false
  setTimeout(() => {
     console.log(currentTarget===null); // false
  }, 0);
 }
<select id="mys">
  <option value="volvo">Volvo</option>
  <option value="saab">Saab</option>
  <option value="mercedes">Mercedes</option>
  <option value="audi">Audi</option>
</select>

答案 3 :(得分:-2)

我建议您尝试使用其他浏览器,因为代码与我合作,我看不到代码段的任何问题。