最近我在做前端面试题总结系列,感兴趣的朋友可以添加关注,欢迎指正、交流。

争取每个知识点能够多总结一些,至少要做到在面试时,针对每个知识点都可以侃起来,不至于哑火。

前言

在上一篇文章【前端 · 面试 】JavaScript 之你不一定会的基础题(一)中,有同学产生了这样一个疑惑:为什么 click 事件的监听函数中,this.idevent.target.id 的输出值是不一样的?

今天我们就来扒一扒这其中的原理。

题目

有如下的 HTML 文档结构:

<div id="parent"><div id="child" class="child">点我</div>
</div>

第一次执行如下 JavaScript 代码:

document.getElementById("parent").addEventListener("click", function () {alert(`parent 事件触发,` + this.id);
});document.getElementById("child").addEventListener("click", function () {alert(`child 事件触发,` + this.id);
});

第二次执行另一套 JavaScript 代码:

document.getElementById("parent").addEventListener("click", function (e) {alert(`parent 事件触发,` + e.target.id);
});document.getElementById("child").addEventListener("click", function (e) {alert(`child 事件触发,` + e.target.id);
});

问题如下:

点击 id 为 child 的 div 后,JavaScript 代码的执行结果分别是什么?

答案是:

  • 第一次结果为:先弹出“child 事件触发,child”,再弹出“parent 事件触发,parent”。
  • 第二次结果为:先弹出“child 事件触发,child”,再弹出“parent 事件触发,child”。

对于这个答案中的第二次输出结果,有人生出了疑惑:为什么 parent 事件触发时,e.target.id 的结果为 child呢?不应该是 parent 吗?

解惑

DOM 元素事件执行顺序

首先,我们知道,HTML 页面上 DOM 元素的事件执行顺序一般有三个阶段:

  • 事件捕获
  • 事件触发
  • 事件冒泡

整个过程如下图:

事件捕获和事件冒泡

当一个事件发生在具有父元素的元素上(例如,在我们的例子中是 child 元素)时,现代浏览器运行两个不同的阶段 - 捕获阶段和冒泡阶段。 在捕获阶段:

  • 浏览器检查元素的最外层祖先<html>,是否在捕获阶段中注册了一个onclick事件处理程序,如果是,则运行它。
  • 然后,它移动到<html>中单击元素的下一个祖先元素,并执行相同的操作,然后是单击元素再下一个祖先元素,依此类推,直到到达实际点击的元素。

在冒泡阶段,恰恰相反:

  • 浏览器检查实际点击的元素是否在冒泡阶段中注册了一个onclick事件处理程序,如果是,则运行它
  • 然后它移动到下一个直接的祖先元素,并做同样的事情,然后是下一个,等等,直到它到达<html>元素。

这两个阶段如下图所示:

在现代浏览器中,默认情况下,所有事件处理程序都在冒泡阶段进行注册,这也是为什么只有一个阻止冒泡方法的方法 event.stopPropagation(),而没有阻止捕获的方法,因为完全没必要。

this 和 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(`parent 事件触发,` + e.target.id);
}, false);document.getElementById("child").addEventListener("click", function (e) {alert(`child 事件触发,` + e.target.id);
}, true);

问题1:如果点击 child 元素,输出是什么?

问题2:如果点击 parent 元素,输出是什么?

可以看到,现在 parent 的点击事件是冒泡阶段执行,child 的点击事件是在 捕获阶段执行。

针对问题1,由于 parent 注册的是冒泡阶段执行,所以它的事件是在 child 触发阶段后的冒泡阶段执行的,所以答案应该是:先弹出 “child 事件触发,child”,再弹出“parent 事件触发,child”。

针对问题二,虽然 child 注册的是捕获阶段执行事件,但是 parent 事件流程的捕获根本走不到它,所以答案应该是:只弹出“parent 事件触发,parent”。

总结

上面我们分析了这么多,其实总结起来就下面几条:

  • event.target 指向触发事件流程的元素,且不会改变。
  • this 指向的是当前所执行事件的注册元素。
  • 捕获止于 event.target,冒泡始于 event.target。
  • 主流浏览器都默认在冒泡阶段进行事件注册,所以,只有阻止冒泡的方法而没有阻止捕获的方法。
  • 元素的 addEventListener 方法中的第三个参数是 true 或者 false,对元素自己触发的事件流程都没有任何影响,只有在它的父元素或者子元素在触发相同的事件后才有影响。

小问题也有大根源,勇于发现,勇于探究!

~

~本文完,感谢阅读!

~

学习有趣的知识,结识有趣的朋友,塑造有趣的灵魂!

大家好,我是〖编程三昧〗的作者 隐逸王,我的公众号是『编程三昧』,欢迎关注,希望大家多多指教!

你来,怀揣期望,我有墨香相迎! 你归,无论得失,唯以余韵相赠!

知识与技能并重,内力和外功兼修,理论和实践两手都要抓、两手都要硬!

【前端 · 面试 】JavaScript 之你不一定会的基础题(二)相关推荐

  1. 前端面试 | JavaScript知识点 | 课程笔记

    前端面试课程笔记 以上方链接内课程内容为主,知识点可能不全面,仅作为自用备忘 Ch3 作用域和闭包 3.1 作用域和自由变量 题目: this的不同应用场景,如何取值? 手写bind函数 实际开发中闭 ...

  2. 前端面试日记(4)- 学而思(笔试+一面+二面)

    笔试 首先说学而思的笔试不是很难,有20个选择题和两个算法题,算法题就是leetcode的#1和#58, 一面 一面没有很难,问了基础的JS,项目,vue知识,收录一下面试题: 基础题没啥说的,可参考 ...

  3. 前端面试CSS自检(上)CSS基础(先看问题 自己自述一遍 不会再看答案 )

    推荐大家的使用本篇文章的方式: 先看问题自己会不会,如果会的话,要自己说一遍,组织好语言. CSS的面试内容主要可以分四个部分: CSS基础.页面布局.定位与浮动和场景应用 CSS部分会涉及到代码的编 ...

  4. 渡一教育公开课web前端开发JavaScript精英课学习笔记(三十二)JavaScript旋转方块

    JavaScript旋转方块 <!DOCTYPE html> <html lang="en"><head><meta charset=&q ...

  5. 三面美团Java岗,面试竟然被这31道Java基础题难倒了

    01 分布式限流:Nginx+ZooKeeper 1.1 分布式限流之Nginx 请解释一下什么是 Nginx? 请列举 x Nginx 的一些特性. 请列举 x Nginx 和 和 Apache 之 ...

  6. 阿里P7大牛亲自教你!面试竟然被这31道Java基础题难倒了

    一.概述 本文主要来分析JMM内存模型,英文名JAVA Memory Model,它是与计算机硬件有关的一个概念.为了保证共享内存的正确性(可见性.有序性.原子性),内存模型定义了共享内存系统中多线程 ...

  7. 前端面试官常问javaScript编程题,隔壁王大爷看了都会了

    目录 1.数组排序. 2.数组元素的去重: 3.用递归的方法求数组的求和: 4.防抖节流的思路. 5.深拷贝.浅拷贝: 6.做一个10秒的倒计时: 7.setTimeout()和setInterval ...

  8. 前端面试常见逻辑题收集及分析

    前端面试中常出现一些有趣的逻辑题,初见的时候有可能会手足无措,但实际多看几个题之后就会有一定的思考逻辑,有种打通任督二脉的感觉.以下是我个人面试经历以及网络上收集来的一些经典题目. 题目: 1.现有一 ...

  9. 前端面试宝典。向未来开启计划

    写在前面 CSDN话题挑战赛第1期 活动详情地址:CSDN 参赛话题:前端面试宝典 话题描述:欢迎各位加入话题创作得小伙伴,如果我没有猜错得话,我觉得你是应该同我一样是一位前端人.如今前端在IT事业中 ...

最新文章

  1. Linux启动过程分析
  2. Android 中 include的使用
  3. 编辑流程图_如何使用ProcessOn快速绘制一张高颜值流程图?
  4. ubuntu 下使用mysql
  5. 对话阿里云MVP裔隽跨界半生,不改赤子心
  6. mysql客户端修改sqlmode_MySQL修改sql_mode
  7. 第64节:Java中的Spring Boot 2.0简介笔记
  8. 如何跨服务器访问html 页面,html页面如何跨域访问另一页面内容,并将部分内容呈现出来?...
  9. 部署前端项目 Linux系统的nginx配置
  10. 012-centos6.5配置静态ip
  11. Unity 2D 跑酷道路动起来
  12. 朋友易得 ,知已难求
  13. 使用第三方登录百度网盘时提示“由于网络原因无法载入页面 请点击刷新后重试”
  14. 北航计算机学院考研英语一还是二,2020北京航空航天大学计算机考研考试科目知多少?...
  15. css点击按钮改变样式
  16. MySQL复制 slave_exec_mode 参数IDEMPOTENT 说明
  17. 简单的有限状态机Unity独家写法(呸~厚颜无耻之人)
  18. prism 计算 Spearman相关
  19. Cheat sheet FOR Python Packages
  20. Java容器类 Collection (set list queue)和map

热门文章

  1. tensorflow-object-detection
  2. poi,HSSFWorkbook,Excel导出,代码示例
  3. ffice 2016 文件运行excel的数据透视表中的数据切片器的时候自动关闭
  4. lstm原文_对时间序列分类的LSTM全卷积网络的见解
  5. 如何修改python代码_解决如何去除Python代码前行号的方法
  6. c语言 单片机模拟,【51单片机】普通I/O口模拟SPI口C语言程序
  7. add git 的文件 移除_【Git第八节】移除文件
  8. 相对定位(HTML、CSS)
  9. ERROR: Could not install packages due to an EnvironmentError: [Errno 13] 权限不够的解决办法
  10. oracle tirger_TPS65130RGETG4_驱动_中文手册(3/10)_TI - 万联芯城