当前位置: 首页 > Web前端 > JavaScript

【前端·面试】你可能不知道的JavaScript基础题(二)

时间:2023-03-27 17:13:57 JavaScript

最近在做前端面试题系列总结。感兴趣的朋友可以加关注,欢迎指正交流。力求每个知识点多总结,至少面试的时候每个知识点都能说的通,不至于哑火。前言在上一篇文章【前端面试】你可能不知道的JavaScript基础问题(一)中,有同学有这样一个疑问:为什么在点击事件的监听函数中,this.id和event.target.id输出值不一样?今天我们就来看看这个原理。该主题具有以下HTML文档结构:Clickme

第一次执行以下JavaScript代码:document.getElementById("parent").addEventListener("click",function(){alert(`parenteventtriggered,`+this.id);});document.getElementById("child").addEventListener("click",function(){alert(`childeventtriggered,`+this.id);});第二次执行另一组JavaScript代码:document.getElementById("parent").addEventListener("click",function(e){alert(`parenteventtriggers,`+e.target.id);});document.getElementById("child").addEventListener("click",function(e){alert(`childeventtriggers,`+e.target.id);});问题如下:点击id为child的div后,JavaScript代码的执行结果是什么?答案是:第一个结果是:先弹出“子事件触发,子”,再弹出“父事件触发,父”。第二次的结果是:先弹出“子事件触发,子”,再弹出“父事件触发,子”。对于这个答案中的第二个输出,有人会有疑惑:为什么触发parent事件时e.target.id的结果是child?不应该是父母吗?迷惑DOM元素事件的执行顺序首先我们知道HTML页面DOM元素的事件执行顺序一般分为三个阶段:事件捕获事件触发事件冒泡整个过程如下图所示:事件捕获和事件冒泡当一个元素被放置在一个父元素上时(例如,在我们的例子中是一个子元素),现代浏览器运行两个不同的阶段——捕获阶段和冒泡阶段。在捕获阶段:浏览器检查元素的最外层祖先,是否在捕获阶段注册了onclick事件处理程序,如果是,则运行它。然后它移动到中被点击元素的下一个祖先并执行相同的操作,然后是被点击的元素和下一个祖先,依此类推,直到它到达实际被点击的元素。在冒泡阶段,恰恰相反:浏览器检查实际点击的元素是否在冒泡阶段注册了onclick事件处理程序,如果是,则运行它然后移动到下一个直接祖先元素,并执行同样的事情,然后是下一个,依此类推,直到到达元素。这两个阶段如下图所示:在现代浏览器中,默认情况下,所有事件处理程序都在冒泡阶段注册,这就是为什么只有一个方法event.stopPropagation()阻止冒泡方法,而没有防止捕获的方法,因为它完全没有必要。这个和event.target首先我们要有一个清晰的认识:事件冒泡或者事件捕获是针对注册了事件的元素。关于this和event.target,总结如下:在整个事件流中,event.target始终指向真正触发事件流的元素,即事件触发阶段的元素。this是正在执行事件的元素的引用,与event.currentTarget指向的元素一致,即当前正在执行哪个元素的监听事件,this和event.currentTarget分别指向哪个元素。event还有一个属性event.srcElement,它是event.target的别名,但属于非标准属性,生产环境中尽量不要使用。如果有如下代码防止冒泡:parent.onclick=function1;child.onclick=function2;当我们点击child时,由于默认会在冒泡阶段注册事件,所以不仅会执行function2,后面还会执行function1,所以结果可能不是我们预期的,我们更喜欢这样他们的点击事件不会互相影响。为此,只需在function2中添加event.stopPropagation()即可。扩展现在我们将在标题中添加另一个JavaScript代码:document.getElementById("parent").addEventListener("click",function(e){alert(`parenteventtriggers,`+e.target.id);},false);document.getElementById("child").addEventListener("click",function(e){alert(`childeventtriggered,`+e.target.id);},true);问题一:如果点击子元素,输出是什么?问题2:如果点击父元素,输出是什么?可以看出父级的点击事件是在冒泡阶段执行的,子级的点击事件是在捕获阶段执行的。对于问题1,由于父注册是在冒泡阶段执行的,其事件是在子触发阶段之后的冒泡阶段执行的,所以答案应该是:先弹出“子事件触发,子”,再弹出“父事件发生,孩子”。对于问题2,子进程虽然在捕获阶段注册了执行事件,但是父事件进程的捕获根本无法去到它,所以答案应该是:只会弹出“父事件触发,父进程”。综上所述,我们上面分析了这么多,其实可以归纳为:event.target指向触发事件流程的元素,不会发生变化。this指向当前执行事件的注册元素。捕获结束于event.target,冒泡开始于event.target。各大浏览器默认在冒泡阶段注册事件,所以只有防冒泡不捕获的方法。元素的addEventListener方法中的第三个参数为true或false,对元素自身触发的事件流没有影响,只有在其父元素或子元素触发相同事件后才会发生。小问题也有大根源,勇于发现和探索!~~本文到此结束,感谢阅读!~学习有趣的知识,认识有趣的朋友,塑造有趣的灵魂!大家好,我是〖编程三昧〗的作者王隐,我的公众号是《编程三昧》,欢迎关注,希望大家多多指教!你来,怀揣期待,我以墨香迎接你!您归来,不分得失,只送回味!知识与技能并重,内功与外功并重,理论与实践两手抓,两手都要用力!