前端面试题2

177 阅读6分钟

面试题总结 www.nowcoder.com/discuss/501…

事件委托

事件具备传播机制:

  1. 从最外层向最里层逐一查找 [捕获阶段:分析出路径]
  2. 把事件源(点击的这个元素)的点击行为触发 [目标阶段]
  3. 按照捕获阶段分析出来的路径, 从里到外, 把每一个元素的点击行为也触发 [冒泡阶段]

事件和事件绑定:

  • 事件是浏览器赋予元素的默认行为
  • 事件绑定是给这个行为绑定一个方法

即便没有给body的点击事件绑定方法, 当点击body的时候,其点击行为也会被触发, 只不过啥事都不做而已

阻止事件传播

  • 包含传播和冒泡(但是不阻止同级别绑定事件)
    e.stopPropagation()

  • 阻止事件传播, 可以把当前元素绑定的其他方法, 如果还未执行, 也不会接着执行了
    e.stopImmediatePropagation()

事件委托\color{green}{事件委托}:

  • 利用时间的传播机制, 实现的一套事件绑定处理方案
  • 例如, 一个容器中, 有很多元素需要在点击的时候做一些事情
  • 传统方案:首先获取需要操作的元素 然后逐一事件绑定
  • 事件委托: 只需要给容器做一个事件绑定
    点击内部任何元素, 根据事件的冒泡传播机制,都会让容器的点击事件也触发. 这里判断事件源, 做相应处理

好处\color{green}{好处}:

  • 提高JS代码运行性能
  • 集中处理逻辑
  • 某些需求,必须基于事件委托处理; 例如: 除了点击xxx外, 点击其余的任何东西都固定做一件事.

限制\color{red}{限制}:

  • 当前事件必须支持事件冒泡 传播机制
  • mouseenter/mouseleave事件没有事件冒泡传播机制
  • 如果单独的事件绑定中, 做了阻止事件传播机制的设定, 事件委托也不会生效

React 合成事件的处理原理

  • 绝对不是给当前元素基于addEventListener单独做的事件绑定
  • React中的合成事件, 都是基于"事件委托"处理的
  • 在React17及以后版本, 都是委托给#root这个容器 [捕获和冒泡都做了委托]
  • 在React17以前, 都是委托给#document [只做了冒泡阶段的处理]
  • 对于没有实现事件传播机制的事件, 才会单独绑定 [mouseenter]

React JSX元素属性中有 onXXX/onXXXCapture这样的属性, 不会给当前元素做事件绑定, 只是把绑定的方法赋值给元素的相关属性

  • onClick 不等于 onclick, 不是DOM0级事件绑定

然后对#root这个容器做了事件绑定 [捕获和冒泡都做了]

  • 因为组件所渲染的内容, 都会插入到#root容器中
  • 这样点击页面的每一个元素, 都会把#root的点击行为触发
  • 而在给#root绑定的方法中, 把之前给元素设置的 onXXX 属性, 在相应阶段执行
ev.stopPropagation(); //合成事件对象中的“阻止事件传播”:阻止原生的事件传播 & 阻止合成事件中的事件传播
ev.nativeEvent.stopPropagation(); //原生事件对象中的“阻止事件传播”:只能阻止原生事件的传播
ev.nativeEvent.stopImmediatePropagation(); //原生事件对象的阻止事件传播,只不过可以阻止#root上其它绑定的方法执行[阻止同级绑定的事件]

从输入URL到页面加载的过程

  • 1.浏览器中输入网址
  • 2.浏览器查找当前URL是否存在缓存,并检查是否过期
    • 如果资源有强缓存,则会直接使用这个缓存的副本,并不再发送请求到浏览器 [通过Expires或Cache-Control字段]
    • 强缓存失效, 会使用协商缓存, 浏览器发送HTTP请求包含if-None-Match或if-Modified-Since头部告诉服务器, 服务器返回200或304
  • 3.通过DNS解析域名的实际IP地址 [本地缓存中有域名解析结果将跳过]
  • 4.与 WEB 服务器建立 TCP 连接 [三次握手]
  • 5.若协议是https则会做加密
  • 6.浏览器发送HTTP请求获取页面html
  • 7.服务器响应html
  • 8.浏览器解析 HTML
  • 9.浏览器渲染页面
  • --根据HTML代码生成DOM tree
  • --根据CSS代码生成CSSOM
  • --将DOMtree和CSSOM整合行程Render Tree
  • --根据Render Tree渲染页面
  • --遇到
  • --直到把Render Tree 渲染完成
  • 10.浏览器解析执行js脚本
  • 11.浏览器发起网络请求
  • 12.服务器响应ajax请求
  • 13.浏览器处理事件循环等异步逻辑

nodejs内存管理和垃圾回收

新生代: 副本整理(Scavenging) -> 堆空间

这个算法主要用于新生代的内存回收。新生代内存被一分为二,一半用来存储对象,一半保持空闲。新创建的对象首先被放在使用区,当使用区快满时,垃圾回收器会标记并复制活着的对象到空闲区,并清除使用区的所有对象,然后交换使用区和空闲区\

如果用到(老生代)会有两个缺点

  • 重复的复制存活对象使得效率低下
  • 空间资源的浪费

老生代: Mark-Sweep 和 Mark-Compact -> 堆空间

标记清除(Mark-Sweep) 这是V8的主要垃圾回收算法,用于回收堆中的大部分内存。首先,垃圾回收器将标记所有根对象,然后标记这些根对象引用的对象,再标记被引用的对象引用的对象,如此递归下去,形成一个引用链。标记完成后,垃圾回收器将清除所有未被标记的对象,这些未被标记的对象即为垃圾
标记整理(Mark-Compact) 为了解决 Mark-Sweep 算法的内存碎片问题,引入了 Mark-Compact(标记整理算法),其在工作过程中将活着的对象往一端移动,这时内存空间是紧凑的,移动完成之后,直接清理边界之外的内存

内存泄漏

程序中己动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果
全局变量 未声明的变量或挂在全局 global 下的变量不会自动回收,将会常驻内存直到进程退出才会被释放,除非通过 delete 或 重新赋值为 undefined/null 解决之间的引用关系,才会被回收
闭包 闭包会引用父级函数中的变量,如果闭包得不到释放,闭包引用的父级变量也不会释放从而导致内存泄漏
谨慎将内存作为缓存 缓存中存储的键越多,长期存活的对象也就越多,垃圾回收时将会对这些对对象做无用功.例如你设置一个map对象, 用来存储用户信息, 那么随着用户增多, map对象会持续增长