Bootstrap

前端面试看似普遍却热度最高的题

一、说一下浏览器事件模型

1、Dom0级别

简单直接,html属性上添加事件函数

<button onclick="handleClick()">Click me</button>

2、Dom1级别

Dom1只是一个规范标准,但并没有明确地引入新的事件模型规范

3、Dom2级别

  1. 特点

    • 引入了更强大、更规范的事件处理机制。
    • 支持事件的捕获和冒泡阶段,可以通过addEventListener方法来添加事件监听器,并可以选择在捕获阶段或冒泡阶段处理事件。
    • 可以为同一个事件添加多个事件处理函数,这些处理函数会按照添加的顺序依次执行,IE会以相反的顺序执行。
    • 无法移除匿名函数。
  2. 代码实例

     const button = document.getElementById('myButton');
     if (button.addEventListener) {
	   // 第三个参数默认是false,表示添加到冒泡阶段,改为true代表事件捕获	
       button.addEventListener('click', handleClick1, false);
       button.addEventListener('click', handleClick2, false);
     } else {
       // IE 兼容性处理
       button.attachEvent('onclick', handleClick1);
       button.attachEvent('onclick', handleClick2);
     }

二、XMLHttpRequest

1、onReadyStateChange方法

监听异步对象请求状态码readyState的改变,每当readyState改变就触发onReadyStateChange事件

2、readyState:请求状态码

  • 0:请求未初始化,还没调用open()
  • 1:服务器连接已建立,还没调用send()
  • 2: 请求已接收,正在处理中,可以从响应中获取内容
  • 3:请求处理中,通常响应中已有部分数据可用了,没有全部完成
  • 4:请求已完成,可以通过异步对象的属性获取数据

3、status:http状态码

  • 1开头,100:continue,101:http->websocket切换更高协议
  • 2开头,200:ok,204:只有响应头无body,206:断点续传分块下载
  • 3开头,301:永久重定向,302:暂时重定向,304:缓存
  • 4开头,400:bad request,403:禁止访问,404:资源不存在,405:方法不可用
  • 5开头,500:服务器错误,501:不支持客户端请求,502:代理服务器异常,503:资源过载

三、fetch与XMLHttpRequest差异

  • fetch使用Promise,写起来更简洁
  • fetch采用模块化设计,API分散在对象上,Request对象、Response对象、Headers对象,更加合理简洁
  • fetch通过数据流(Stream对象)获取数据,可以分块读取,减少内存占用,对于大文件和网络慢情况有用。XMLHttpRequest必须放在缓存里,不支持分块读取,必须全部拿到后一次性吐出来

四、说说闭包的作用和坑

闭包是指在函数内可访问外层函数变量的函数。

1、特点

  • 变量持久性,不会因为外部函数执行结束而垃圾回收
  • 数据隐藏,外部无法直接访问闭包内部变量,只能通过闭包提供的接口

2、作用

  • 控制访问:模块化编程,封装私有属性
  • 函数柯里化:将多参函数转为一系列单参函数
  • 单例模式
  • react hooks

3、问题坑和解决方案

问题:内存泄露

解决方法:

  • 1.及时清理不必要的引用,不需要时将外部变量设置为nul
  • 2.避免循环引用
  • 3.及时清理定时器和事件监听
  • 4.通过Performance中的memory截取快照比对,看有没有内存泄漏

五、this指向问题

this绑定的5种方式

  • 默认绑定(非严格模式下this指向全局对象, 严格模式下this会绑定到undefined)
  • 隐式绑定(当函数引用有上下文对象时, 如 obj.foo()的调用方式, foo内的this指向obj)
  • 显示绑定(通过call()或者apply()方法直接指定this的绑定对象, 如foo.call(obj))
  • new绑定(使用new来调用一个函数,会构造一个新对象并把这个新对象绑定到调用函数中的this)
  • 箭头函数绑定(this的指向由外层作用域决定的,this 绑定的是最近一层非箭头函数的 this,否则,thisundefined)

六、什么是事件委托及作用

  • 事件委托是把一个或一组事件委托到父级或更外层元素上,真正绑定事件的是外层元素。
  • 事件流经过三个阶段:捕获阶段–目标阶段–冒泡阶段,事件委托发生在冒泡阶段
  • 当事件响应在目标元素上时,会通过冒泡机制从而触发外层元素的绑定事件上,然后在外层元素上执行函数

七、事件循环

1、执行步骤

  1. 首先执行同步任务。
  2. 当所有同步任务执行完毕后,检查并执行微任务队列中的所有微任务。
  3. 微任务队列清空后,从宏任务队列中取出一个宏任务并执行。
  4. 一个宏任务执行完毕后,再次检查并执行微任务队列,然后继续执行下一个宏任务,如此循环。

2、宏任务与微任务

微任务:Promise \ MutationObserver

宏任务:通常包括setTimeoutsetIntervalXMLHttpRequest回调函数、事件监听器回调函数等

八、构造器创建对象与class有什么区别?

  1. 构造器可以不通过new,但class一定需要
  2. 对于属性和方法的共享,构造器必须通过原型上才能实现
  3. class声明的内部方法都是不可枚举的
  4. class内可以使用get和set关键字,拦截该属性的存取函数
  5. class声明类不存在变量提升

九、浏览器从输入url到渲染全过程

  1. 应用层:解析url,对域名进行DNS查询获取IP地址,构建Http报文请求
  2. 传输层:通过3次握手构建TCP连接
  3. 网络层:将TCP段中的Http请求封装成IP数据包传输
  4. 数据链路层:将IP数据包封装成帧
  5. 服务端数据链路层:查看mac地址是否匹配,将帧解析成IP数据包
  6. 服务端网络层:查看IP地址是否匹配,将IP数据包解析成TCP段返回给客户端
  7. 客户端:响应并显示页面,对html解析生成DOM树,css资源对DOM树渲染,JS资源对DOM树动态修改

十、DNS解析过程

本地–根服务器–顶级域名服务器–权威域名服务器–IP地址

  1. 输入URL后,缓好是否有,有返,没有下一步
  2. 查操作系统缓存有没有
  3. 向本地DNS服务器发查询清求,本地查缓存有没有,没有的话向根域名服务器发起查询
  4. 根服务器返回顶级域名服务器地址
  5. 本地DNS服务器向顶级域名服务器发起查询,顶级域名服务器返回权威服务器地址
  6. 本地向权威服务器查询,权威返回IP地址
  7. 本地将IP地址返给浏览器

十一、强制缓存、协议缓存和cdn缓存的区别

1、强制缓存

通过设置cache-control相对时间比如20s

  • no-cache:用协议缓存
  • no-store:不用缓存
  • public:无条件缓存,用的最多
  • private:只针对单个用户浏览器缓存

2、协议缓存

也叫对比缓存,当强制缓存失效后使用

  • Last-Modified / If-Modified-Since:服务器设置“Last-Modified”告知资源最后修改时间,浏览器通过“If-Modified-Since”带上上次最后修改时间,如果一样使用304缓存
  • ETag / If-None-Match:Etag是服务器生成的唯一标识,浏览器通过“If-None-Match”带上ETag值,比对是否一致,如果一直使用304缓存

3、CDN缓存

CDN 会根据用户的 IP 地址将请求转发到距离用户最近的边缘节点服务器上,特点是就近访问、负载均衡、独立缓存

十二、如何监控js异常

1、代码内方式监控

  • try…catch
  • window.onerror,全局的错误处理函数,可以捕获未被try...catch捕获的运行时错误,包括异步错误(在浏览器环境中)。
  • Promise的错误可以通过.catch()方法来处理,未被处理的Promise错误会被全局的unhandledrejection事件捕获。

2、埋点方式

通过PerformanceObserver获取主要数据指标:

  • FP:First Paint 首次绘制
  • LCP(Largest Contentful Paint):最大内容绘制
  • CLS Cumulative Layout Shift:累积布局偏移

3、通过Chrome devTool监控

  • 断点调试:在 “Sources”(源代码)选项卡中,找到你的 JavaScript 文件,在代码行号处点击可以设置断点
  • Performance面板:可以点击Record录制,查看Main线程,分析页面加载和执行过程中的各个任务,包括脚本执行、布局、绘制等。可以查看每个任务的耗时和调用栈,以便找出性能瓶颈
  • “Memory”(内存)选项卡可以用于分析页面的内存使用情况。

4、React框架内

使用ErrorBoundary包裹组件,对报错信息记录,当js出现错误时不显示组件

十三、react与vue的区别

1、React

react通过Scheduler和Fiber架构一级高效率的diff调度算法实现了异步可中断的更新

1. Scheduler:

  • 通过重写 requestIdleCallback(在不支持的浏览器中使用 setTimeout 模拟)等机制,React 可以在每一个时间片(大约 5ms)内执行一部分任务。如果在一个时间片内没有完成当前任务,它会保存当前的状态,让出主线程的控制权,等待下一个时间片继续执行,从而实现可中断与恢复.
  • 不同的更新任务可以有不同的优先级。高优先级的任务(如用户交互产生的更新)可以中断低优先级的任务,优先得到处理。

2. Fiber

  • React Fiber 使用了双缓冲的 Fiber 树机制。在更新过程中,会构建一棵新的 Fiber 树(称为“workInProgress 树”),同时保留旧的 Fiber 树(“current 树”)。当新树构建完成后,通过指针切换,瞬间将新树变为当前树进行渲染,避免了一次性大规模的 DOM 操作,提高了更新的效率和性能。
  • 作为静态的数据结构来说
    每个Fiber节点对应一个React element,保存了该组件的类型(函数组件/类组件/原生组件…)、对应的DOM节点等信息;
  • 作为动态的工作单元来说
    每个Fiber节点保存了本次更新中该组件改变的状态、要执行的工作(需要被删除/被插入页面中/被更新…)

3.Diff算法

  • 算法改进,通过比较类型和关键属性如key,判断哪些节点需要被更新,避免整体节点树的遍历更新。
  • 只对同级元素进行diff
  • 不同类型的元素直接删除重建
  • 开发者可以通过key判断哪些元素在不同的渲染下保持稳定。

2、Vue2响应式原理及问题

1.数据劫持

  • Vue 会遍历传入的对象的所有属性,使用Object.defineProperty()将这些属性转换为 getter 和 setter。
  • 当属性被读取时,会触发 getter 方法;当属性被修改时,会触发 setter 方法。

2.依赖收集与触发更新

  • 当一个 Vue 实例被创建时,会进行初始化过程,这个过程中会对模板中用到的数据进行 “依赖收集”。
  • 会将当前的依赖(通常是一个 Watcher 实例,表示一个正在观察数据变化的组件实例或计算属性等)添加到该数据的依赖列表中。
  • 当数据被修改时,会触发 setter 方法,在 setter 方法中,会通知所有依赖该数据的 Watcher 进行更新操作,Watcher 会触发相应的组件重新渲染。

3.问题

  • 无法检测到对于对象属性的添加删除,需用用Vue.set()更新
  • 无法检测数组索引的变化和长度变化,需要用pushpopshiftunshiftsplicesortreverse等方法触发更新
  • 对于大型数据对象,遍历所有属性并使用Object.defineProperty()进行数据劫持会有一定的性能开销。

3、Vue3响应式原理

1.数据代理

Vue3使用Proxy对象来代理原始数据对象。Proxy可以拦截对目标对象的各种操作,如属性读取、设置、删除等。当对代理对象进行操作时,Proxy可以触发相应的拦截器函数,从而实现对数据的响应式处理。

性能更好:

因为Proxy是在对象级别进行拦截,而不是对每个属性进行单独处理。

十三、关于项目优化

1、webpack

  • 分包拆包,将公共包common和业务包business分开,common包通过提前加载和缓存应用,实现可复用
  • tree-shaking,对第三库的引用,只保留引用的部分,未使用的部分shake掉,不打进包内
  • 组件按需应用,使用Babel-plugin-import,配合tree-shaking使用
  • uglifyjs对js文件进行压缩
  • CDN加速

2、架构优化

  • 容器优化:容器单实例实现

原生端创建一个react instance manage,同时留一个备份,通过这个容器加载common包,打开页面时把业务的bundle包load进去

每次打开页面都使用已有的实例,不需要等待实例加载

  • 预加载功能:前置加载数据

加载引擎的同时,根据业务包的描述文件开一个线程,提前获取数据

  • RN降级:有开关,在跳转时进行判断(阿波罗配置)

3、组件优化

  • 异步加载:react-lazyload 的核心原理是监听元素是否进入可视区域,当元素进入可视区域时才触发实际的加载操作。对于长列表加载场景,这一特性非常有用。
  • 使用React.memo({data}=>return<></>)防止组件过多渲染
  • 使用useMemo记忆计算结果,避免在每次渲染时都进行昂贵的计算
  • 副作用操作(如网络请求、订阅事件等)应该在 useEffect 中进行,而不是在组件的渲染函数中。这样可以确保渲染函数的纯粹性,减少不必要的重新渲染触发。

4、页面加载

  • 首屏加载优化,首次只加载首屏内的组件,之外的组件通过异步加载方式加载
  • 首屏接口切分,防止首屏接口过大影响数据获取速度
  • 非敏感信息进行缓存,用户切换页面时可第一时间看到新的页面信息

十四、HTTP 和 HTTPS 的区别

1、安全性方面

1. 加密方式

  • HTTP:不进行加密,数据以明文形式在网络中传输,存在极大安全风险,任何人截取数据包后可轻松读取敏感信息。
  • HTTPS:使用 SSL 或 TLS 协议进行加密,在客户端和服务器之间建立加密通信通道,数据被加密为密文,难以被破解。

2. 证书认证

  • HTTP:无证书要求,通信不需要进行身份验证,容易遭受中间人攻击。
  • HTTPS:服务器需向权威证书颁发机构申请数字证书,客户端验证证书合法性,确保连接真实可信,证书无效或有问题时客户端会发出警告阻止连接建立。

2、连接方式方面

1. 端口号

  • HTTP:默认使用 80 端口进行通信。
  • HTTPS:默认使用 443 端口进行通信。

2. 连接建立过程

  • HTTP:连接建立相对简单,客户端发送请求,服务器响应请求后开始数据传输。
  • HTTPS:连接建立过程复杂。客户端发送请求,服务器返回数字证书,客户端验证证书合法性,若有效则生成随机密钥并用服务器公钥加密后发送给服务器,服务器用私钥解密得到随机密钥,双方用此密钥进行加密解密以安全传输数据。

3、性能方面

1. 传输速度

  • HTTP:不进行加密和证书验证等操作,传输速度相对较快。
  • HTTPS:因需进行加密和证书验证等操作,会消耗一定计算资源和时间,传输速度相对较慢,但随着硬件性能提升和加密算法优化,性能差异在逐渐减小。

2. 资源消耗

  • HTTP:对服务器和客户端资源消耗较小。
  • HTTPS:服务器进行证书管理和加密解密等操作会消耗更多 CPU 和内存资源,客户端在验证证书和进行加密解密时也会消耗一定资源。

4、适用场景方面

1. 一般应用场景

  • HTTP:适用于对安全性要求不高的场景,如公开信息网站、博客等。
  • HTTPS:适用于对安全性要求较高的场景,如电子商务网站、网上银行、企业内部管理系统等,涉及用户隐私信息和重要业务数据传输。

2. 搜索引擎优化(SEO)

  • 一些搜索引擎会给予 HTTPS 网站更高权重,认为其更安全可靠,对于希望在搜索引擎中获得更好排名的网站,采用 HTTPS 可能有一定优势。

十五、前端安全防御方式:

  1. 定期更新登录组件参数、收银台组件,保持和银行内最新规范同步。
  2. 针对跨站脚本攻击XSS,输入输出验证,过滤转义符号。同源策略:在 HTML 页面的 <head> 标签中,你可以通过添加 Content Security Policy 来限制页面加载的资源来源
  3. 跨站请求伪造(CSRF),关键信息请求携带token。使用同源策略限制外部网站对用户数据的访问
  4. 使用 X-Frame-Options 头部,可以禁止网页被嵌入到 iframe 中,从而预防点击劫持
  5. 使用 HTTPS 加密数据传输,可以有效防止在数据传输过程中被窃听或篡改

悦读

道可道,非常道;名可名,非常名。 无名,天地之始,有名,万物之母。 故常无欲,以观其妙,常有欲,以观其徼。 此两者,同出而异名,同谓之玄,玄之又玄,众妙之门。

;