一、HTML
1. 前端页面有哪三层构成,分别是什么?作用是什么?
前端页面主要由三层构成,分别是结构层、样式层和行为层。这三层各自的作用如下:
1. HTML(HyperText Markup Language):结构层,它是网页的基础,用于定义网页的内容结构,如标题、段落、列表、图像等元素。HTML标签告诉浏览器如何组织和呈现这些内容。
2. CSS(Cascading Style Sheets):样式层,CSS负责为HTML元素添加样式,如颜色、字体、布局、间距等,使得内容具有视觉吸引力并适应不同的设备和屏幕尺寸。通过媒体查询,可以实现响应式设计。
3. JavaScript(JS):行为层,JavaScript是动态交互的核心,它使网页能够响应用户的操作,执行复杂的逻辑,比如表单验证、动画效果、数据绑定等。现代前端开发还可能用到框架和库(如React、Vue或Angular)来简化开发过程。
2. 行内元素有哪些?块级元素有哪些? 空(void)元素有哪些?
1. 行内元素不独占一行,不可以设置宽高。例如:
<a>、<b>、<em>,<span>、<img>、<input>、 <strong>等。
2. 块级元素占据一行,可以设置宽高。例如:
<div>、<p>、<h1>~<h6>、<ul>、<ol>、<li>、<table>、<form> 等。
3. 空元素,也称为无内容元素,它们不包含任何内容,但可以有属性。它们通常用于定义结构,不会影响布局。例子有:
<hr>(水平线)、<br>(换行)、<img>(图片,当src为空时)、<input type="hidden"> 等。
3. 怎么解决2个行内块元素中间的空白
导致原因:元素被当成行内元素排版的时候,元素之间的空白符(空格、回车换行等)都会被浏览器处理,根据white-space的处理方式(默认是normal,合并多余空白),原来HTML代码中的回车换行被转成一个空白符,所以元素之间就出现了空隙。
方案一:手动取消空格和换行,(不推荐)
方案二:父元素设置font-size:0px(推荐)
4. 页面导入样式时,使用link和@import有什么区别?
区别一:加载方式和顺序
页面被加载时,link 会同时被加载,而 @import 引用的 CSS 会等到页面被加载完再加载。
区别二:权重区别
link 方式的样式的权重高于 @import 权重。
区别三:从属关系区别
link 属于 HTML 标签,而 @import 是 CSS 提供的。
区别四:兼容性区别
link 没有兼容性问题,@import 不兼容 ie5 以下。
5. title与h1的区别、b与strong的区别、i与em的区别?
title:概括了网站信息,可以告诉搜索引擎或者用户关于这个网站的内容主题是什么,优化seo
h1:文章主题内容,告诉蜘蛛我们的网站内容最主要是什么
b标签只有加粗的样式,没有实际含义。
strong表示标签内字符比较重要,向屏幕阅读器和搜索引擎表明这段文字的强调重要性。
i只是一个倾斜标签,没有实际含义。
em表示标签内字符重要,向屏幕阅读器和搜索引擎表明这段文字的强调重要性。
6. img标签的title和alt有什么区别?
title : 鼠标移入到图片展示文字值
alt : 图片无法显示时展示文字值
7. iframe的优点和缺点?
用于嵌入另一个 HTML 文档或外部资源(如网页、视频、地图等)到当前页面中。
优点:
- 嵌入外部内容: <iframe> 允许你在一个网页中嵌入来自不同源或服务器的内容,这有助于创建丰富多彩的页面。
- 独立性: 内嵌的内容在 <iframe> 中运行,与主页面相互隔离,这意味着它不会受到主页面的影响,保持了独立性。
- 简便性: 使用 <iframe> 非常简单,只需提供要嵌入的资源的 URL 或相对路径即可。
缺点:
- 性能问题: 如果滥用 <iframe>,在同一个页面中加载多个 <iframe> 可能会导致性能问题,因为每个 <iframe> 都需要单独加载资源。
- 可访问性问题: 内嵌内容可能导致可访问性问题,因为屏幕阅读器等辅助技术可能无法正确解释和浏览 <iframe> 内的内容。
- 安全性风险: 如果未谨慎处理来自不受信任源的内容,可能会存在安全风险,例如点击劫持(clickjacking)攻击。
8.对 HTML 语义化的理解?
语义化是指使用适当的 HTML 标签来表达页面内容的结构和含义
语义化的好处:
- 语义化使代码更具可读性,结构清晰,便于团队开发和维护
- 语义化有利于用户体验, 使屏幕阅读器和其他辅助技术能够更好地理解页面结构
- 语义化有利于SEO
9.优雅降级渐进增强?
渐进增强:确保网页在任何环境下都能正常工作。在此基础上,逐步增加更丰富的功能和体验,针对支持更高级技术的设备或浏览器提供更好的交互体验。
优雅降级:首先设计和实现一个功能丰富、交互性强的版本,针对现代浏览器和设备进行优化。当用户使用老旧的浏览器或设备时,系统会逐渐“降级”功能或界面,保证即使功能有所减少,用户仍能正常使用。
10.HTTP的几种请求方法用途
1. GET
用途:用于从服务器获取资源(如网页、图片、文件等)。
2. POST
用途:用于向服务器发送数据,通常用于提交表单数据或上传文件。
3. PUT
用途:用于更新服务器上的资源,通常是全量更新,即替换资源。
4. PATCH
用途:用于部分更新资源,通常是更新资源的一部分,而不是替换整个资源。
5. DELETE
用途:用于删除服务器上的资源。
6. HEAD
用途:与GET方法相似,但只请求资源的头部信息,不返回资源的实际内容。用于获取元数据,如文档的大小、修改日期等。
7. OPTIONS
用途:用于获取服务器支持的请求方法,或者用于跨域请求(CORS)。
8. TRACE
用途:用于诊断和调试,返回服务器接收到的请求内容。客户端通过TRACE请求可以看到服务器收到的请求报文。
9. CONNECT
用途:用于建立一个到服务器的隧道连接,通常用于HTTPS请求的代理。
11.前端需要注意哪些SEO?
- 合理的title、description,keywords:搜索引擎对着这项的权重逐个减小
- 语义化的HTML代码,符合W3C规范:语义化代码让搜索引擎容易理解网页
- 少用iframe:搜索引擎不会抓取iframe中的内容
- 非装饰性图片必须加alt
- 提高网站速度:网站速度是搜索引擎排序的一个重要指标
12.script标签中defer和async的区别
用于控制 JavaScript 脚本的加载和执行时机
属性 | 加载顺序 | 执行顺序 | 执行时机 | 适用场景 |
---|---|---|---|---|
defer | 按顺序加载 | 按顺序执行(HTML顺序) | HTML解析完毕后执行 | 当脚本依赖于DOM结构时使用 |
async | 并行加载 | 按照脚本加载完成的顺序执行 | 脚本加载完成后立即执行 | 当脚本不依赖于DOM时使用 |
13.Canvas和SVG区别
Canvas:画布,通过Javascript来绘制2D图形,是逐像索进行渲染的。其位置发生改变,就会重新
进行绘制。
SVG:缩放矢量图形是基于可扩展标记语言XML的2D图的语言。
14.严格模式与混杂模式如何区分
严格模式:又称为标准模式,指浏览器按照 w3C 标准解析代码
混杂模式: 又称怪异模式、兼容模式,是指浏览器用自己的方式解析代码。混杂模式通常模拟老式
浏览器的行为,以防止老站点无法工作
15.浏览器的内核有哪些?分别有什么代表的浏览器?
IE : trident 内核
Firefox : gecko 内核
Safari : webkit 内核
Opera(欧朋):以前是 presto 内核, Opera 现已改用Google - Chrome 的 Blink 内核
Chrome:Blink (基于 webkit ,Google与Opera Software共同开发)
16.浏览器是如何渲染页面的?
17.TCP为什么需要三次握手和四次挥手
三次握手是为了建立可靠的数据传输通道,四次挥手则是为了保证等数据完成的被接收完再关闭连
接。
18.HTML5新特性
1. 语义化标签
2. 多媒体元素
3. Canvas
<canvas>
元素用于绘制图形、图像或动画,可以通过 JavaScript 动态控制其内容
4. 本地存储
5. 新的表单类型
email:能够验证当前输入的邮箱地址是否合法
color : 提供了一个颜色拾取器
number: 只能输入数字,其他输入不了
6.DOM查询操作
document.querySelector()
document.querySelectorAll()
7.拖放
19.DNS
DNS 协议是互联网的核心协议之一,用于将域名(如 www.example.com
)转换为对应的 IP 地址(如 93.184.216.34
),从而实现域名到 IP 地址的解析。
负载均衡:通过配置多个 IP 地址对应一个域名,DNS 可以根据策略(如轮询、地理位置等)将流量分配到不同的服务器。
故障转移:DNS 协议可以实现故障转移。如果主服务器不可用,DNS 可以将流量重定向到备用服务器
20.冒泡捕获
JS事件冒泡和事件捕获_js事件冒泡和事件捕获是什么-CSDN博客
21.浏览器存储
1. Cookie
-
特点:
-
小型文本数据(最大约 4KB),随HTTP请求自动发送到服务器。
-
可设置过期时间(会话Cookie或持久Cookie)。
-
-
优点:
-
兼容性极好(所有浏览器支持)。
-
适合存储少量敏感数据(如会话ID),支持服务端读取。
-
-
缺点:
-
容量小,频繁传输增加带宽消耗。
-
安全性较低(易被XSS或CSRF攻击)。
-
需手动解析键值对。
-
2. Web Storage
分为 localStorage
和 sessionStorage
:
-
特点:
-
纯键值存储(字符串类型),容量约 5~10MB(因浏览器而异)。
-
localStorage
永久存储,sessionStorage
会话结束时清除。
-
-
优点:
-
操作简单(
setItem/getItem
),不随请求发送到服务器。 -
适合存储客户端非敏感数据(如用户偏好)。
-
-
缺点:
-
仅支持字符串,需手动序列化复杂数据(如JSON)。
-
同源策略限制,跨域不可访问。
-
无自动过期机制(需代码维护)。
-
3. IndexedDB
-
特点:
-
浏览器端的非关系型数据库,支持事务、索引,容量大(通常 ≥250MB)。
-
异步API,适合存储复杂结构化数据。
-
-
优点:
-
高性能查询,支持二进制数据(如文件)。
-
适合离线应用或大量数据缓存(如PWA)。
-
-
缺点:
-
API复杂(需处理回调或Promise)。
-
兼容性问题(旧浏览器如IE10+支持但不完善)。
-
二、CSS
1. 介绍一下CSS的盒子模型
CSS的盒子模型有哪些:标准盒子模型、IE盒子模型
W3C的标准盒模型:在标准的盒子模型中,width指content部分的宽度
IE的盒模型:在IE盒子模型中,width表示content+padding+border这三个部分的宽度
通过CSS如何转换盒子模型:
box-sizing: content-box; /*标准盒子模型*/
box-sizing: border-box; /*IE盒子模型*/
2.css 选择器优先级
!important > 行内样式(比重1000)> ID 选择器(比重100) > 类选择器(比重10) > 标签(比
重1) > 通配符 > 继承 > 浏览器默认属性
3.哪些属性可以继承
- font 相关属性:font-size、font-weight、line-height。
- color:控制文本颜色。
- text 相关属性:text-align、text-decoration、letter-spacing、word-spacing。
- visibility:控制元素是否可见。
- cursor:指定鼠标悬停在元素上时的光标样式。
- list-style 相关属性:包括 list-style-type、list-style-position、list-style-image。
4.垂直居中几种方式
- 将显示方式设置为表格, display:table-cell ,同时设置 vertial-align:middle
- 使用 flex 布局,grid布局,设置为 align-item:center
- top: 50%; left: 50%; transform: translate(-50%, -50%);
- 文本垂直居中设置 line-height 为 height 值
5.rgba和opacity的透明效果有什么不同
- Rgba即可以指定元素颜色也可以指定透明度,opacity只能控制元素透明度不能设置颜色
- Rgba透明度是基于实际颜色,而opacity是针对元素本身透明度设置
- 支持rgba的浏览器比支持opacity的更普遍,但是在低版本的ie中rgba不被支持而支持opacity
6. display的block,inline和inline-block区别
block : 会独占一行,多个元素会另起一行,可以设置width、height、margin和padding属性;
inline : 元素不会独占一行,设置width、height属性无效。但可以设置水平方向的margin和
padding属性,不能设置垂直方向的padding和margin;
inline-block:行内块级元素类似于行内元素,它不会独占一行,允许设置宽度和高度。
7.隐藏元素的方法有哪些?
display: none: 渲染树不会包含该染对象,因此该元素不会在页面中占据位置,也不会响应绑定的
监听事件。
visibility: hidden: 元素在页面中仍占据空间,但是不会响应绑定的监听事件
opacity: 0: 将元素的透明度设置为 0,以此来实现元素的隐藏。元素在页面中仍然占据空间,并且
能够响应元素绑定的监听事件
position: absolute: 通过使用绝对定位将元素移除可视区域内,以此来实现元素的隐藏
z-index: 负值: 来使其他元素遍盖住该元素,以此来实现隐藏
transform: scale(0,0): 将元索缩放为 0,来实现元素的隐藏。
8.transition和animation区别?
- 触发方式不同: transition 通过 CSS 属性值的变化来触发动画效果,而 animation 则需要通过设置关键帧(keyframes)来指定动画序列。
- 控制方式不同: transition 只能控制开始和结束状态之间的过渡动画,而 animation 可以指定多个关键帧,控制元素动画的每一个阶段,包括动画开始、中间和结束的时刻、变换状态以及持续时间等。
- 耗费资源不同:相对来说, animation 消耗的浏览器资源更多,因为它需要计算多个关键帧之间的动画效果,而 transition 只需在两种状态之间进行简单的计算即可。
- 兼容性不同: transition 相对来说更加兼容不同的浏览器,而 animation 在某些旧版浏览器上可能无法正常工作。
9.如何用CSS画一个三角形
用边框画(border),例如:
{
width: 0;
height: 0;
border-left:100px solid transparent;
border-right:100px solid transparent;
border-top:100px solid transparent;
border-bottom:100px solid #ccc;
}
10.单行文本溢出
div{
width: 200px; /* 容器宽度 */
white-space: nowrap; /* 不换行 */
overflow: hidden; /* 超出部分隐藏 */
text-overflow: ellipsis; /* 溢出部分显示省略号 */
}
11.定位
position 值 | 定位依据 | 是否脱离文档流 | 说明 |
---|---|---|---|
static | 元素在文档流中的原始位置 | 否 | 默认定位,无法使用 top 、left 等 |
relative | 相对于元素的原始位置偏移 | 否 | 元素相对于其原始位置偏移 |
absolute | 相对于最近的已定位祖先元素 | 是 | 元素脱离文档流并根据祖先元素定位 |
fixed | 相对于浏览器窗口定位 | 是 | 元素固定在视口中,滚动时不移动 |
sticky | 相对于滚动位置定位 | 否 | 元素在滚动时,达到指定位置后固定 |
12.对BFC规范的理解
是什么:BFC就是页面上一个隔离的独立容器,在一个 BFC 中,元素的布局不会影响外部元素,而外部的元素也不会影响 BFC 内部的元素。
以下情况会触发 BFC(使元素创建一个新的 BFC):
float
:元素设置为float
,不论是左浮动 (float: left
) 还是右浮动 (float: right
),都会创建一个 BFC。position
:元素设置为absolute
或fixed
,也会创建一个 BFC。display
:以下display
值会创建 BFC:display: inline-block
display: table
display: flex
display: grid
display: flow-root
(用于触发新的 BFC)
overflow
:当overflow
被设置为auto
、scroll
或hidden
时,元素也会创建一个 BFC。
BFC的应用场景:
- 防止边距折叠
- 清除浮动
13. 简述什么是伪元素和伪类,并列举一些自己知道的伪元素和伪类
伪元素:是用于创建并操作元素的特定部分,它可以在DOM中创建一个不存在的元素,并为其添加样式。
::before:在元素内容之前插入内容
::after:在元素内容之后插入内容
::first-line:选择元素的第一个行
::first-letter:选择元素的第一个字母
伪类:是用于选择元素的特定状态或行为的关键词,它可以应用于已存在的元素。
:hover:当鼠标悬停在元素上时应用的样式
:active:元素正在被用户交互(如点击)时应用的样式
:focus:元素获得焦点(如键盘焦点或点击)时应用的样式
:nth-child(n):选择父元素的第n个子元素
:not(selector):选择不匹配给定选择器的元素
14.回流和重绘
回流:回流是指当页面的布局发生改变时,浏览器需要重新计算元素的尺寸和位置。如修改元素的尺寸,位置。添加、删除或修改 DOM 元素。
重绘:重绘是指当元素的外观(如颜色、背景、阴影等)发生变化时,浏览器需要重新绘制这些元素,但不涉及重新计算其位置和尺寸。
回流一定会造成重绘,重绘不一定会造成回流。
那么要避免回流和重绘:
css方面
* 使用transform替代top等位移 ;
* 使用visibility替换display: none;
* 避免使用table布局 ;
* 尽可能在DOM树的最末端改变class;
* 避免设置多层内联样式,尽量层级扁平;
* 将动画效果应用到position属性为absolute或fixed的元素上;
* 避免使用CSS表达式;
* 将频繁重绘或者回流的节点设置为图层,比如 video, iframe ;
* CSS3硬件加速(GPU加速) ,可以是transform: translateZ(0)、opacity、 flters、 Will-change提前告诉浏览器元素会发生什么变化;
JS方面
* 避免频繁操作样式,合并操作;
* 避免频繁操作DOM,合并操作;
* 防抖节流控制频率;
* 避免频繁读取会引发回流/重绘的属性,比如上面的C、O、S属性
* 对具有复杂动画的元素使用绝对定位。
15.CSS3新特性
1. 选择器
- 属性选择器:允许选择包含特定属性的元素,如
[type="text"]
。 - 伪类:
nth-child()
、nth-of-type()
、:first-child
、:last-child
等,提供更灵活的选中方式。 - 伪元素:
::before
和::after
,允许在元素前后插入内容。 - :not():允许选中不符合某个条件的元素,例如
div:not(.active)
。
2. 边框(Border)
CSS3 对边框做了大量改进,增加了新的样式:
- border-radius:可以让元素的边框变为圆角,支持圆形、椭圆形等各种形状。
- border-image:允许用图片来做元素的边框,而不仅仅是颜色。
- box-shadow:为元素添加阴影效果。
- text-shadow:为文本添加阴影效果。
3. 背景(Background)
- background-size:允许设置背景图片的大小,支持
cover
和contain
等关键字来控制图像的缩放。 - background-clip:定义背景的裁剪区域,支持
content-box
、padding-box
和border-box
。 - multiple backgrounds:允许一个元素使用多个背景图像,通过逗号分隔多个
background-image
。 - linear-gradient 和 radial-gradient:CSS3 支持渐变背景,创建线性渐变和径向渐变效果,而无需图像。
4. 变换(Transform)
5. 过渡(Transition)
6. 动画(Animation)
7. Flexbox 布局和网格布局
8. 媒体查询(Media Queries)
16.随着屏幕缩放,图片能够自适应保持长宽等比为16:9或者1:1,图片不能压缩
要实现在屏幕缩放时,图片能够自适应并保持长宽比为 16:9 或 1:1,同时又不能被压缩,可以通过 CSS 的 object-fit
属性来实现。object-fit
属性用于指定替换元素(如 <img>
标签)的内容应该如何适应其容器。
<style>
.image-container {
width: 100%; /* 容器宽度自适应 */
max-width: 100%; /* 不超过100% */
height: auto; /* 高度自动调整 */
aspect-ratio: 16 / 9; /* 设置长宽比为16:9 */
display: block;
overflow: hidden;
}
img {
width: 100%; /* 图片宽度自适应 */
height: 100%; /* 图片高度自适应 */
object-fit: cover; /* 保持长宽比,不拉伸 */
}
</style>
</head>
<body>
<div class="image-container">
<img src="https://via.placeholder.com/800x450" alt="image">
</div>
17.响应式布局和自适应布局
区别 | 响应式布局 | 自适应布局 |
---|---|---|
布局调整方式 | 页面根据屏幕尺寸动态调整布局。 | 根据设备类型或尺寸加载不同的布局版本。 |
布局代码 | 使用一个布局,通过媒体查询和流式布局调整。 | 为不同的设备编写多个布局,通常由脚本或服务器加载。 |
灵活性 | 高度灵活,适应各种屏幕尺寸和设备。 | 灵活性较低,针对特定设备优化设计。 |
实现方式 | 通过 CSS 媒体查询、百分比宽度等实现。 | 通过 JavaScript 或服务器端检测加载不同布局。 |
适用范围 | 适用于响应各种屏幕尺寸的设备。 | 适用于需要为不同设备提供不同用户体验的场景。 |
开发复杂度 | 较低,代码重复较少。 | 较高,需要为每个设备编写独立的布局。 |
三、JS
1. JS 数据类型
基本类型:string、number、boolean、undefined、null、symbol、bigint(sbnu)
引用类型:object
NaN是一个数值类型,但是不是一个具体的数字。
2.null和undefined的区别
1. 作者在设计js的都是先设计的null(为什么设计了null:最初设计js的时候借鉴了java的语言)
2. null会被隐式转换成0,很不容易发现错误。
3. 先有null后有undefined,出来undefined是为了填补之前的坑。
具体区别:JavaScript的最初版本是这样区分的:null是一个表示"无"的对象(空对象指针),转为数值时为0;undefined是一个表示"无"的原始值,转为数值时为NaN。
3.数组常用方法
增:
- push() 向数组的末尾添加一个或更多元素,并返回新的长度
- unshift() 在数组开头添加任意多个值,然后返回新的数组长度
- concat() 首先会创建一个当前数组的副本,然后再把它的参数添加到副本末尾,最后返回这个新构建的数组,不会影响原始数组
删:
- pop() 方法用于删除数组的最后一项,同时减少数组的 length 值,返回被删除的项
- shift() 方法用于删除数组的第一项,同时减少数组的 length 值,返回被删除的项
- slice() 传入两个参数,分别是开始位置和结束位置,不包括结束值,返回一个新数组,不影响原数组
改:
- splice() 传入三个参数,分别是开始位置,要删除元素的数量,要插入的任意多个元素,返回删除元素的数组,对原数组产生影响
-
增加 let arr = [1, 2, 3, 4, 5]; arr.splice(2, 0, 'a', 'b'); // 从索引2开始,删除0个元素,插入'a'和'b' console.log(arr); // 输出: [1, 2, 'a', 'b', 3, 4, 5] 删除 let arr = [1, 2, 3, 4, 5]; arr.splice(1, 2); // 从索引1开始,删除2个元素 console.log(arr); // 输出: [1, 4, 5] 替换 let arr = [1, 2, 3, 4, 5]; arr.splice(2, 1, 'a'); // 从索引2开始,删除1个元素,插入'a' console.log(arr); // 输出: [1, 2, 'a', 4, 5]
查:
- indexOf() 返回要查找的元素在数组中的位置,如果没找到则返回 -1
- includes() 返回要查找的元素在数组中的位置,找到返回 true ,否则 false
- find() 返回第一个匹配的元素
es6:
forEach()
map()
filter()
reduce()
4.JavaScript字符串的常用操作方法有哪些
增:
- 字符串可以通过‘+’以及${}进行字符串拼接
- concat 用于将一个或多个字符串拼接成一个新字符串
删:三个函数都接收一个或两个参数,跟数组中slice相似
- slice()
- substr() 接受两个参数:起始索引和要提取的字符数
- substring() 接受两个参数:起始索引和结束索引 不包括结束位置的字符
改:
- trim()、trimLeft()、trimRight() 删除前、后或前后所有空格符,再返回新的字符串
- repeat() 接收一个整数参数,表示要将字符串复制多少次,然后返回拼接所有副本后的结果
- padStart()、padEnd() 复制字符串,接收两个参数,第一个参数是长度,第二个参数是想要
- 填充的字符,如果小于指定长度,则在相应一边(end/start)填充字符,直至满足长度条件
- toLowerCase()、 toUpperCase() 大小写转化
查:
- chatAt() 返回给定索引位置的字符,由传给方法的整数参数指定
- indexOf() 从字符串开头去搜索传入的字符串,并 返回位置 (如果没找到,则返回 -1 )
- startWith() 从字符串中搜索传入的字符串, 判断开头字符串是否与期待值相同 ,并返回一个表示是否包含的布尔值
- includes() 从字符串中搜索传入的字符串, 判断字符串是否包含期待值 ,并返回一个表示是否包含的布尔值
5.“ ===”、“ ==”的区别
==: 用于比较两个操作数的值。如果它们相等,则返回 true
- 两个都为简单类型,字符串和布尔值都会转换成数值,再比较
- 简单类型与引用类型比较,对象转化成其原始类型的值,再比较
- 两个都为引用类型,则比较它们是否指向同一个对象
- null 和 undefined 相等
- 存在 NaN 则返回 false
===:只有在无需类型转换运算数就相等的情况下,才返回 true,需要检查数据类型
区别:
相等操作符(==)会做 类型转换 ,再进行值的比较,全等运算符不会做类型转换
隐式转化题:
6.箭头函数有哪些特点
- 不拥有自己的
this
,this
会继承自外部上下文。 - 没有
arguments
对象。 - 不能作为构造函数使用。
7.var、let、const 区别
-
var
:具有函数作用域,存在变量提升,允许重复声明,适合旧代码或特定场景。 -
let
:具有块级作用域,存在暂时性死区,允许重新赋值,适合局部变量。 -
const
:具有块级作用域,存在暂时性死区,不允许重新赋值,适合声明常量。
8. new操作符具体干了什么呢
1. 创建一个空对象
new
操作符首先会创建一个空对象 {}
。这个对象将成为新实例的基础。
2. 设置原型链
新创建的对象指向构造函数的 prototype
属性。这意味着新对象可以通过原型链访问构造函数的 prototype
上的属性和方法。
3. 执行构造函数
new
操作符会将构造函数的 this
绑定到新创建的对象上,并执行构造函数的代码。
4. 返回新对象
如果构造函数没有显式返回一个对象,则 new
操作符会自动返回步骤 1 中创建的空对象(此时已经被构造函数中的代码修改过)。如果构造函数显式返回一个对象,则返回该对象;如果返回的是非对象类型(如字符串、数字等),则忽略返回值,仍然返回步骤 1 中创建的对象。
9.深拷贝浅拷贝的区别?如何实现一个深拷贝?
1. 浅拷贝
浅拷贝是指创建一个新对象,然后将当前对象的拷贝到新对象中。如果属性值是引用类型(如对象、数组等),则只拷贝引用而不拷贝引用的对象本身。因此,原始对象和拷贝对象会引用同一个内存地址。
使用 Object.assign()
Object.assign()
方法可以将一个或多个源对象的属性复制到目标对象中,实现浅拷贝。
扩展运算符
使用 Array.from()
const originalArray = [1, 2, { nested: 'value' }];
const shallowCopyArray = Array.from(originalArray);
console.log(shallowCopyArray); // [1, 2, { nested: 'value' }]
2. 深拷贝
深拷贝是指创建一个新对象,然后递归地将原对象中的所有属性值(包括嵌套的对象、数组等)拷贝到新对象中。深拷贝会创建一个完全独立的副本,原始对象和拷贝对象之间没有任何引用关系。
3. 如何实现一个深拷贝?
- 方法 1:使用 JSON 序列化和反序列化
- 方法 2:递归实现
- 方法 3:使用库
10. 对作用域链的理解
当代码中引用一个变量时,JavaScript 引擎会从当前作用域开始查找,如果找不到,就会沿着作用域链向上查找,直到找到该变量或到达全局作用域。
作用域链的构成顺序如下:
-
局部作用域(Local Scope):当前函数或块级作用域。
-
父级作用域(Parent Scope):嵌套的外部函数或块级作用域。
-
全局作用域(Global Scope):最顶层的作用域,通常对应
window
(浏览器)或global
(Node.js)。
11. js原型链
1. 什么是原型(Prototype)?
在 JavaScript 中,每个对象都有一个特殊的属性,称为原型([[Prototype]]
)。这个属性指向另一个对象,称为该对象的原型对象。原型对象可以包含一些属性和方法,这些属性和方法可以通过原型链被继承。
2. 什么是原型链?
原型链是 JavaScript 中对象之间的一种链式关系。当访问一个对象的属性或方法时,如果该对象本身没有这个属性或方法,JavaScript 引擎会沿着原型链向上查找,直到找到该属性或方法,或者到达链的末端(null
)。
12.伪数组转换为数组
伪数组是一种类数组对象,它具有类似数组的结构和特性,但并不是真正的数组。
在 JavaScript 中,常见的伪数组包括函数参数 arguments 、DOM 元素集合 NodeList 和
HTMLCollection 等。
伪数组和数组区别:
伪数组没有数组的方法和属性(如 push、pop、length), 不能使用数组相关的循环方法 (如
forEach、map、reduce)等。但它们具有类数组的结构, 可以通过下标来访问元素,并且拥有
length 属性
转换: Array.from() 方法或者扩展运算符
13.for…in 和 for … of区别
1. for...in
for...in
用于遍历对象的可枚举属性。不仅会遍历对象自身的属性,还会遍历其原型链上的可枚举属性
2. for...of
for...of
是 ES6 引入的语法,用于遍历可迭代对象(如数组、字符串、Map、Set、NodeList 等)的值。它不能直接用于普通对象。
14..数组扁平化
- 使用递归
- 使用 reduce 方法:reduce 方法可以用来将数组中的每个元素累加到一个结果中
- 使用 flat 方法:ES2019 中引入了数组的 flat 方法,可以将嵌套的数组扁平化成一维数组。
15.判断一个对象为空对象
let objs = {}
Object.keys(objs).length //0
16.map和set
Map :可迭代的集合,其中每个元素都由一个键和一个相应的值组成。 Map 中的键可以是任
何类型,而值也可以是任何类型,包括对象引用和原始值。
Set :一种只含有唯一值的集合,不允许出现重复项。 Set 中的值可以是任何类型,包括对
象引用和原始值。
17. 数组去重
var arr = [1, 1, 1, 15, 6, 7, 7, 34, 2, 43, 2, 66, 3, 3];
<script>
var arr = [1, 1, 1, 15, 6, 7, 7, 34, 2, 43, 2, 66, 3, 3];
--------------------------------------------------------
1.碰到相同的就删掉
//方法一:升序比较
for (var i = 0; i < arr.length; i++) {
for (var j = i + 1; j < arr.length; j++) {
if (arr[i] === arr[j]) {
arr.splice(j, 1);
j--; //因为删掉了一个元素,就要把j减一,否则会漏掉一个元素未比较
}
}
}
//方法二:降序比较
for (var i = 0; i < arr.length; i++) {
反方向比较
for (var j = arr.length - 1; j > i; j--) {
if (arr[i] === arr[j]) {
arr.splice(j, 1);
}
}
}
--------------------------------------------------------
2.用indexof查找,
indexOf()返回指定元素在数组中第一次出现的索引,
如果数组中不存在该元素,则返回 -1。
//方法一:for
var newArr = [];
for (var i = 0; i < arr.length; i++) {
// 如果新数组里没有该数字,就添加进去
if (newArr.indexOf(arr[i]) === -1) {
newArr.push(arr[i]);
}
}
console.log(newArr);
//方法二:forEach
var newArr = [];
arr.forEach((item, index) => {
if (newArr.indexOf(item) === -1) {
newArr.push(item);
}
});
console.log(newArr);
//方法三:for+indexof
var newArr = [];
for (var i = 0; i < arr.length; i++) {
// 在原数组中比较 索引值和查找到的相等的添加到新数组
if (arr.indexOf(arr[i]) === i) {
newArr.push(arr[i]);
}
}
console.log(newArr);
//方法四:filter
indexof只查找第一次出现数字的的索引,
故而 重复的元素的索引不等于indexof出的索引
var newArr = arr.filter((item, index) => arr.indexOf(item) === index);
console.log(newArr); // [1, 15, 6, 7, 34, 2, 43, 66, 3]
--------------------------------------------------------
3.用includes判断是否包含,包含返回true
//方法一:for
var newArr = [];
for (var i = 0; i < arr.length; i++) {
// 如果新数组不包含该数字就添加进去
if (!newArr.includes(arr[i])) {
newArr.push(arr[i]);
}
}
console.log(newArr);
4.Set
var newarr = Array.from(new Set(arr));//或 [...new Set(array)];
console.log(newarr);
18.数组乱序
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
arr.sort(() => Math.random() - 0.5)
19.数组some函数和every函数
特性 | some() | every() |
---|---|---|
功能 | 检查是否至少有一个元素满足条件 | 检查是否所有元素都满足条件 |
返回值 | 只要有一个元素满足条件,返回 true | 所有元素都满足条件,返回 true |
遍历行为 | 一旦找到满足条件的元素,立即返回 true ,停止遍历 | 一旦找到不满足条件的元素,立即返回 false ,停止遍历 |
空数组的返回值 | 返回 false | 返回 true |
典型用途 | 检查数组中是否存在某种情况 | 确保数组中所有元素都符合某种情况 |
20.闭包
什么是闭包
函数定义和函数表达式位于另一个函数的函数体内。
而且,这些内部函数可以访问它们所在的外部函数中声明的所有局部变量、参数和声明的其他内部函数。
闭包的用途
(1)数据封装和模块化
闭包可以用来创建模块化的代码,隐藏内部实现细节,只暴露必要的接口。
(2)函数工厂
闭包可以用来创建函数工厂,根据不同的参数生成不同的函数。
(3)缓存和记忆化
闭包可以用来实现缓存机制,保存函数的计算结果,避免重复计算。
优点
-
数据封装和隐私保护。
-
创建函数工厂,生成可配置的函数。
-
实现缓存和记忆化,优化性能。
-
用于事件处理和异步编程,保存状态。
缺点
-
可能导致内存泄漏,尤其是捕获大型对象时。
-
过多的闭包可能影响性能,增加内存占用。
-
调试复杂,尤其是嵌套闭包或捕获多个变量时。
21. 请解释一下 JavaScript 的同源策略?
同源策略是浏览器的一个重要的安全机制,用于限制来自不同源(Origin)的文档或脚本之间的交互能力。它的核心目的是防止恶意网站读取或篡改用户在其他网站上的敏感数据,从而保护用户的安全和隐私。
什么是“同源”?
在浏览器中,同源是指两个页面或资源具有相同的协议(Protocol)、域名(Domain)和端口(Port)。如果这三个部分完全相同,则认为它们是同源的;否则,它们就是跨源的。
22.哪些操作会导致内存泄漏
- 未使用 var 声明的全局变量
- 闭包函数
- 循环引用(两个对象相互引用)
- 控制台日志( console.log )
- 移除存在绑定事件的 DOM 元素( IE )
- setTimeout 的第一个参数使用字符串而非函数的话,会引发内存泄漏
23.事件循环
JavaScript 是一门 单线程 的语言,意味着同一时间内只能做一件事,而实现单线程非阻塞的方法就是事件循环
在 JavaScript 中,所有的任务都可以分为
同步任务:立即执行的任务,同步任务一般会直接进入到主线程中执行
异步任务:异步执行的任务,比如 ajax 网络请求, setTimeout 定时函数等
同步任务进入主线程,异步任务进入任务队列,主线程内的任务执行完毕为空,会去
任务队列读取对应的任务,推入主线程执行。上述过程的不断重复就事件循环
24.判断一个值是什么类型有哪些方法
- typeof 运算符
- instanceof 运算符
instanceof
用于判断一个对象是否是某个构造函数的实例。 -
const arr = [1, 2, 3]; console.log(arr instanceof Array); // true
- Object.prototype.toString.call 方法
- constructor 属性指向对象的构造函数。
-
const arr = [1, 2, 3]; console.log(arr.constructor === Array); // true
25.Promise
1. Promise 是什么?
Promise
是一个表示异步操作最终完成(或失败)结果的对象。它是一种用于处理异步操作的编程模式,解决了传统回调函数嵌套(回调地狱)的问题。
Promise
有三种状态:
-
Pending(进行中):初始状态,既不是成功,也不是失败。
-
Fulfilled(已成功):操作成功完成,此时可以获取操作的结果。
-
Rejected(已失败):操作失败,此时可以获取失败的原因。
一旦 Promise
的状态从“进行中”变为“已成功”或“已失败”,它的状态就固定下来,不会再改变。
Promise
支持链式调用,因为 .then()
和 .catch()
方法返回的都是一个新的 Promise
2. Promise 的静态方法
Promise
提供了一些静态方法,用于简化常见的异步操作:
-
Promise.all
:接受一个Promise
数组,当所有Promise
都成功时返回一个包含所有结果的数组,如果有任何一个失败,则返回失败的Promise
。 -
Promise.race
:接受一个Promise
数组,返回第一个完成的Promise
的结果。 -
Promise.any
:接受一个Promise
数组,返回第一个成功完成的Promise
的结果,如果所有都失败,则返回失败。
3.async/await
async/await
是基于 Promise
的语法糖。await
实际上是等待一个 Promise
的结果,而 async
函数返回的也是一个 Promise
对象。它们的出现是为了简化 Promise
的链式调用,让异步代码看起来更像是同步代码
四 、Vue
1. 谈谈你对MVVM开发模式的理解?
MVVM分为Model、View、ViewModel三者。
Model 代表数据模型,数据和业务逻辑都在Model层中定义;
View 代表UI视图,负责数据的展示;
ViewModel 负责监听 Model 中数据的改变并且控制视图的更新,处理用户交互操作;
这种模式实现了 Model 和 View 的数据自动同步,因此开发者只需要专注对数据的维护操作即可,
而不需要自己操作 dom。
MVC
MVC通过分离 Model、View 和 Controller 的方式来组织代码结构。 用户与页面产生交互时
Controller 中的事件触发器就开始工作了,通过调用 Model 层,来完成对 Model 的修改,然后
Model 层再去通知 View 层更新
2. v-if 和 v-show 有什么区别?
v-if是动态的向DOM树内添加或者删除DOM元素;
v-show是通过设置DOM元素的display样式属性控制显隐;
v-show
不会导致 DOM 的重新渲染,因此在频繁切换显示状态时性能更好。
3.route和router区别
route指的是当前路由的信息对象,包含路径、参数、查询等;而router是Vue Router的实例,用于管理路由,比如导航到不同路由。
4.vue自定义指令
局部注册 :directive选项
全局注册 :main.js,app.vue如上引入
5. Vue2和Vue3响应式原理
1. Vue 2 的响应式原理
(1)基于 Object.defineProperty
Vue 2 使用 Object.defineProperty
来实现响应式系统。这个方法允许 Vue 为对象的属性添加 getter 和 setter,从而在属性被访问或修改时触发依赖追踪和更新。
(2)依赖追踪和发布-订阅模式
Vue 2 的响应式系统基于发布-订阅模式:
-
每个响应式属性都有一个对应的
Dep
(依赖)实例,用于存储依赖该属性的订阅者(如渲染函数)。 -
当属性被访问时,当前的依赖会被添加到
Dep
中。 -
当属性被修改时,
Dep
中的所有订阅者会被触发,从而更新视图。
2. Vue 3 的响应式原理
(1)基于 Proxy
Vue 3 使用 Proxy
来实现响应式系统。
-
拦截操作:Vue 3 使用
Proxy
的handler
方法(如get
、set
、deleteProperty
等)来拦截对象的操作。 -
动态响应式:
Proxy
可以动态地拦截对象的所有操作,包括新增属性、删除属性等,从而解决了 Vue 2 中的限制。
(2)依赖追踪和副作用函数
Vue 3 的响应式系统基于副作用函数(Effect Function):
-
每个响应式操作都会触发一个副作用函数(如组件的渲染函数)。
-
Vue 3 使用一个全局的副作用函数栈来管理当前的副作用函数。
-
当属性被修改时,依赖列表中的所有副作用函数会被触发,从而更新视图。
(3)性能优化
Vue 3 的响应式系统在性能上有显著提升:
-
细粒度的依赖追踪:Vue 3 可以精确地追踪每个属性的依赖关系,从而减少不必要的更新。
-
支持
Proxy
:Proxy
可以拦截对象的几乎所有操作,包括Object.keys
、for...in
等,从而解决了 Vue 2 中的限制。 -
懒执行:Vue 3 的副作用函数默认是懒执行的,只有在需要时才会触发更新。
6.vue和react共同点?区别
共同点 :
- 数据驱动视图
- 组件化
- 都使用 Virtual DOM(虚拟节点)
不同点 :
核心思想不同
vue定位就是尽可能的降低前端开发的门槛,vue的主要特点:渐进式框架
React是函数式编程(纯组件)
组件写法
React推荐的做法是 JSX + inline style , 也就是把 HTML 和 CSS 全都写进 JavaScript
中
Vue 推荐的做法是 template 的单文件组件格式,即html,css,JS 写在同一个文件
响应式原理
vue2采用object.defineProperty ,vue3采用proxy
React基于状态机,手动优化,数据不可变,需要 setState 驱动新的state替换老的
state
7.vue双向数据绑定原理
Vue 的双向数据绑定通过双向数据绑定是通过 v-model
实现的,原理基于 数据劫持 和 事件监听
1. 数据劫持(通过 Object.defineProperty
或 Proxy
)
Vue 通过劫持数据,监听数据的变化。当数据被修改时,Vue 能够捕获到这些变化,并触发视图的更新。
-
Vue 2.x:使用
Object.defineProperty
劫持数据的getter
和setter
。 -
Vue 3.x:使用
Proxy
替代Object.defineProperty
,因为Proxy
提供了更强大的拦截能力,支持对整个对象的拦截,而不仅仅是单个属性。
2. 事件监听
Vue 通过监听 DOM 事件(如 input
、change
)来捕获用户输入的变化,并更新数据。
v-model
是一个语法糖,它背后实际上是绑定了两个操作
v-model分为两部分,通过v-bind绑定值,再通过v-on:input来修改值
8.computed和watch区别
computed计算属性,watch监听属性
computed中有get和set方法,会默认缓存计算结果。
watch不支持缓存,支持异步
computed
缓存的原理
基于 Vue 的响应式系统和依赖追踪机制
当一个 computed
属性被定义时,Vue 会自动追踪其依赖的响应式数据。这些依赖数据的变化会触发 computed
属性的重新计算。
(1)首次计算与缓存
-
当
computed
属性首次被访问时,Vue 会执行其计算函数,计算出结果并将其缓存起来。 -
同时,Vue 会记录下计算过程中访问的所有响应式依赖。
(2)依赖变化检测
-
当依赖项发生变化时(例如,某个
ref
的值被更新),Vue 会标记这个computed
属性为“过期”(dirty)。 -
这意味着
computed
的缓存值不再有效,需要重新计算。
(3)惰性重新计算
-
当
computed
属性再次被访问时,Vue 会检查它是否被标记为“过期”。-
如果是“过期”状态,Vue 会重新执行计算函数,更新缓存值。
-
如果不是“过期”状态(即依赖项未变化),Vue 直接返回缓存值,避免重复计算。
-
9.Vuex
- State => 基本数据,定义了应用状态的数据结构,可以在这里设置默认的初始状态。
- Getter =>
state
中派生的计算属性,用于从state
中获取复杂的数据。Getter 的作用类似于 Vue 中的计算属性 - Mutation =>唯一可以更改 Vuex 中
state
的方法。Mutation 必须是同步函数,因为 Vuex 的状态变化需要是可追踪的 - Action => 是一个可以包含异步逻辑的函数,用于提交 Mutation
- Module => 模块化Vuex,允许将单一的 Store 拆分为多个 store 且同时保存在单一的状态树
- 中。
10.vue组件通讯方式
1、通过props传递:父组件通过props向子组件传递数据。子组件通过props接收父组件传递的数据。这种方式适用于父子组件之间的通信。
2、通过emit触发自定义事件:子组件通过emit触发一个事件,父组件监听这个事件来接收数据。这种方式适用于子组件向父组件传递数据。
3、使用ref:父组件可以通过$refs直接访问子组件的实例,从而调用子组件的方法或访问其数据。这种方式适用于父子组件之间的直接交互。
4、EventBus(全局事件总线):通过创建一个事件总线,实现非父子关系的组件之间的通信。这种方式适用于兄弟组件或跨多级的组件通信。
5、Vuex:Vuex是一个状态管理库,适用于大型应用中组件间的状态管理。通过改变状态来通知其他组件更新。
6、provide/inject:provide和inject可以实现跨级组件的数据传递。provide在祖先组件中提供数据,inject在后代组件中注入数据。
7、attrs/listeners:attrs用于父传子,子传孙的情况;listeners用于孙传子的反向通信。这种方式适用于祖先与后代组件之间的数据传递。
8、插槽(Slots):插槽用于父组件向子组件插入内容,也可以用于子组件向父组件传递数据。
9、路由传参:通过路由的params和query参数进行组件间的数据传递。这种方式适用于通过路由进行的数据传递。
11.vue3setup的父传子怎么去写
第一种:使用vue2写法通过props和$emit
第二种:script中setup
vue3自带defineProps,defineEmits
12.生命周期
生命周期阶段 | 钩子函数 | 触发时机 | 用途 |
---|---|---|---|
创建阶段 | setup() | 组件初始化时,替代 beforeCreate 和 created | 初始化响应式数据、定义方法 |
挂载阶段 | onBeforeMount | 组件挂载到 DOM 之前 | 适合模板预处理,此时还不能操作 DOM |
onMounted | 组件挂载到 DOM 之后 | 适合初始化第三方库、操作 DOM | |
更新阶段 | onBeforeUpdate | 数据更新但 DOM 未重绘之前 | 适合在 DOM 更新前处理逻辑 |
onUpdated | 数据更新且 DOM 重绘之后 | 适合在数据更新后操作 DOM | |
卸载阶段 | onBeforeUnmount | 组件销毁之前 | 适合清理工作,如移除事件监听、定时器 |
onUnmounted | 组件销毁之后 | 适合销毁后的清理工作 | |
错误处理 | onErrorCaptured | 捕获组件内部错误 |
在 Vue 2 中,this.$el 和 this.$data 都是 Vue 实例的属性,代表不同的内容。
1. this.$el
this.$el 是 Vue 实例的根 DOM 元素,它指向 Vue 实例所控制的根节点元素。在 Vue 中,el 是在 Vue 实例创建时,指定的根元素(即 Vue 实例挂载到哪个 DOM 元素上)。
2. this.$data
this.$data 是 Vue 实例的数据对象,它包含了 Vue 实例的响应式数据。你可以通过 this.$data 访问 Vue 实例内部的数据。
父组件引入子组件,那么生命周期执行的顺序是?
父: beforeCreate、created、beforeMount
子: beforeCreate、created、 beforeMount、mounted
父:mounted
beforeCreate和created有什么区别?
beforeCreate没有$data
created中有$data
created是可以拿到methods的方法的
beforeCreate拿不到methods的方法
发送请求在created还是mounted?
-
created
:适用于依赖数据渲染的场景,可以尽早发送请求,减少用户等待时间。 -
mounted
:适用于需要操作 DOM 的场景,确保 DOM 已经挂载,避免 DOM 操作相关的问题。
这个问题具体要看项目和业务的情况了,因为组件的加载顺序是,父组件引入了子组件,那么先执行父的前3个生命周期,再执行子的前4个生命周期,那么如果我们的业务是父组件引入子组件,并且优先加载子组件的数据,那么在父组件中当前的请求要放mounted中,如果当前组件没有依赖关系那么放在哪个生命周期中请求都是可以的。
raect的生命周期
-
挂载阶段(Mounting):组件被创建并插入 DOM。
-
更新阶段(Updating):组件因
props
或state
变化而重新渲染。 -
卸载阶段(Unmounting):组件从 DOM 中移除。
1. 挂载阶段(Mounting)
组件首次被渲染到 DOM 时的生命周期方法:
constructor()
-
作用:初始化
state
或绑定方法。
render()
-
作用:返回 JSX,描述 UI。
-
调用时机:必须调用,负责渲染组件。
componentDidMount()
-
作用:组件挂载后执行(DOM 已渲染完成)。
2. 更新阶段(Updating)
组件因 props
或 state
变化而重新渲染时的生命周期方法:
static getDerivedStateFromProps(props, state)
(同上)
-
调用时机:每次
render
前(包括更新阶段)。
shouldComponentUpdate(nextProps, nextState)
-
作用:决定组件是否重新渲染(性能优化)。
-
调用时机:
props
或state
变化时,在render
前调用。
render()
-
调用时机:每次更新时都会调用。
componentDidUpdate(prevProps, prevState, snapshot)
-
作用:DOM 更新后执行(如 AJAX 请求、手动 DOM 操作)。
3. 卸载阶段(Unmounting)
组件从 DOM 中移除时的生命周期方法:
componentWillUnmount()
-
作用:清理副作用(如取消订阅、清除定时器、关闭 WebSocket)。
React Hooks 替代方案(函数组件)
现代 React 推荐使用 Hooks 替代类组件的生命周期:
生命周期方法 | Hooks 替代方案 |
---|---|
constructor | useState |
componentDidMount | useEffect(..., []) |
componentDidUpdate | useEffect(..., [deps]) |
componentWillUnmount | useEffect(() => cleanup) |
shouldComponentUpdate | React.memo / useMemo |
13.Vue 中 CSS scoped 的原理
添加scoped标签后会给组件中所有标签元素,添加一个唯一标识,这个唯一标识就是自定义属
性,data-v-xxxxxxxx这样的字眼
14.$nextTick原理
Vue 的 DOM 更新机制
在 Vue 中,数据的响应式更新是异步的。当数据发生变化时,Vue 不会立即更新 DOM,而是将这些更新操作放入一个队列中,然后在下一个“tick”中统一处理。这种机制可以避免不必要的重复DOM 操作
$nextTick
的原理
DOM 更新完成后执行回调。在数据变化后获取更新后的 DOM,避免因 DOM 更新延迟导致的错误
15.data是函数不是对象
vue是一个单页面应用,最终所有的实例都会挂载到app.vue文件,如果data是一个对象那么会导致
数据污染。通过函数返回对象的方式,利用函数作用域的限制避免数据污染
16.路由守卫机制
-
全局守卫:适用于所有路由跳转,如权限验证、日志记录。
-
路由独享守卫:适用于特定路由,如特定页面的权限验证。
-
组件内守卫:适用于组件级别的路由行为,如数据预加载、导航取消
17.vue2和vue3区别
1. 性能优化
Vue 3
-
更小的体积和颗粒度:Vue 3 的核心库体积更小,通过 Tree-shaking 可以进一步优化打包大小。
Vue 2
-
响应式限制:使用
Object.defineProperty
,无法检测对象属性的动态添加或删除。
2. 响应式系统
Vue 3
-
基于
Proxy
:Vue 3 使用Proxy
实现响应式系统,支持动态属性的响应式更新。 -
细粒度依赖追踪:能够更精确地追踪依赖关系,减少不必要的渲染。
-
更好的数组响应式:
Proxy
可以拦截数组的所有操作,如索引赋值、新增元素等。
3. 组合式 API(Composition API)
Vue 3
-
新增 Composition API:Vue 3 引入了组合式 API,允许开发者以函数的形式组织逻辑,更灵活地复用代码。
-
setup
函数:组件的逻辑可以在setup
函数中定义,支持ref
、reactive
、computed
等 API。 -
更好的类型支持:Composition API 提供了更好的 TypeScript 支持,便于类型推导。
Vue 2
-
仅支持 Options API(选项式API)
4. 模板语法
Vue 3
-
v-if
和v-for
的优先级
18.v-if和v-for 优先级,不建议一起使用
在 Vue 2.x 中,v-for
的优先级高于 v-if
。这意味着在同时使用时,v-for
会先执行,然后对每个循环的元素应用 v-if
的条件判断。
-
在 Vue 2.x 中,
v-for
的优先级高于v-if
,这意味着即使v-if
的条件为false
,v-for
仍然会对每个元素进行渲染,只是最终不会将其插入到 DOM 中。 -
在 Vue 3.x 中,虽然
v-if
的优先级高于v-for
,但仍然不推荐同时使用,因为这会导致不必要的计算和 DOM 操作。
19.Vue3.0 所采用的 Composition Api (组合式)与 Vue2.x 使用的 Options Api(选项式) 有什么不同?
-
选项式将代码按选项(如
data
、methods
、computed
、watch
等)分类。 -
组合式将代码按逻辑功能组织,使用
setup
函数集中管理。
- options Api 当组件变得复杂,导致对应属性的列表也会增长,这可能会导致组件难以阅读和理解 。composition Api它将功能定义在一起,利于查找和理解
- Composition API 对 tree-shaking 友好,代码也更容易压缩
- Composition API 中见不到 this 的使用,减少了 this 指向不明的情况
20.vue组件和插件的区别
组件 : Vue 组件是一个可复用的 Vue 实例,可以带有自己的状态和方法。组件可以包含其他组
件,从而形成一个复杂的 UI 列表。
优点
- 可以将代码封装成一个可复用的组件,提高开发效率。
- 组件具有良好的可维护性,易于修改和更新。
缺点
- 组件的功能和作用比较独立,不太适用于全局功能的扩展。
- 组件的管理和组织需要一定的规范,否则可能会导致混乱和不易维护。
插件 : Vue 插件可以扩展 Vue 的全局功能,在应用程序中可以重复使用。常见的插件如 vue-
router 、 vuex 、 axios 等。
优点
- 插件可以方便地扩展 Vue 的全局功能。
- 插件可以使代码重复利用,提高开发效率。
- 开源社区中已经有大量的插件可以用于解决常见的问题。
缺点
- 插件具有一定的复杂性,需要更多的学习成本。
- 插件功能可能比较复杂,可能会导致性能下降。
21.vue修饰符
在 Vue 中,修饰符处理了许多 DOM 事件的细节
表单修饰符
- .lazy 懒加载,光标离开标签时,才赋值给value
- .trim 过滤首位空格
- .number 限制输入类型为数字或转为数字
事件修饰符
- .stop 阻止事件冒泡
- .prevent 阻止事件默认行为
- .once 事件只触发一次
鼠标按键修饰符
- left 左键点击
- right 右键点击
- middle 中键点击
22.history和hash两种模式有什么区别
hash : hash 模式是一种把路由路径用井号 # 拼接 URL 后面的模式。
- 优点:浏览器兼容性较好,连 IE8 都支持
- 缺点:路径在井号 # 的后面,比较丑
- seo不友好
history : history API 是 H5 提供的新特性,允许开发者直接更改前端路由,即更新浏览器 URL
地址而不重新发起请求
- 优点:路径比较正规,没有井号 #
- 缺点:兼容性不如 hash,且需要服务端支持,否则一刷新页面就404了
- seo友好
23.params和query区别
params 和 query 都是用于传递参数的,但它们的传参方式和使用场景是不同的
params
是通过路由的路径传递参数,通常用于定义动态路由。路径参数是 URL 的一部分,以冒号 :
开头。
query
是通过 URL 的查询字符串传递参数,通常用于分页、搜索等场景。查询参数以 ?
开头,多个参数用 &
分隔。
24.单页应用如何提高加载速度
- 使用代码分割:将代码拆分成小块并按需加载(懒加载),以避免不必要的网络请求和减少加载时间。
- 缓存资源:利用浏览器缓存来存储重复使用的文件,例如 CSS 和 JS 文件、图片等。
- 预加载关键资源:在首次渲染之前,先提前加载关键资源,例如首页所需的 JS、CSS 或数据,以保证关键内容的快速呈现。
- 使用合适的图片格式:选择合适的图片格式(例如 JPEG、PNG、WebP 等),并根据需要进行压缩以减少文件大小。对于一些小图标,可以使用 iconfont 等字体文件来代替。
- 优化 API 请求:尽可能地减少 API 调用的数量,并使用缓存和延迟加载等技术来优化 API 请求的效率。
25.vue的diff算法
深度解析面试题:Vue的diff算法 一篇带你搞懂!_vue diff算法面试题-CSDN博客
当组件创建和更新时,vue均会执行内部的update函数,该函数在内部调用render函数生成虚拟dom树,组件会指向新树,然后vue将新旧两树进行对比,找到差异点,最终更新到真实dom。对比差异的过程叫diff。
在对比时,vue采用深度优先、逐层比较的方式进行比对。 在判断两个节点是否相同时,vue是通过虚拟节点的key和tag来进行判断的。具体来说,首先对根节点进行对比,如果相同,则将旧节点关联的真实dom的引用挂到新节点上,然后根据要更新属性到真实dom,然后再对比其子节点数组;如果不相同,则按照新节点的信息递归创建所有真实dom,同时挂到对应虚拟节点上,然后移除掉旧的dom。
在对比其子节点数组时,vue对每个子节点数组使用了两个指针,分别指向头尾,然后不断向中间靠拢来进对比,这样做的目的是尽量复用真实dom,尽量少的销毁和创建真实dom。如果发现相同,则进入和根节点一样的对比流程,如果发现不同,则移动真实dom到合适的位置。
这样一直递归的遍历下去,直到整棵树完成对比。
26.SPA单页面,优缺点
SPA 是一种现代的 Web 应用架构
用户首次访问应用时,整个应用只有一个 HTML 页面,通过 JavaScript 动态加载,所有页面切换和数据更新都通过 JavaScript 动态完成,而不需要重新加载整个页面。
SPA 的优点
(1)用户体验更流畅
-
无需重新加载页面:页面切换和数据更新都是动态完成的
-
快速响应:用户操作后,页面内容可以即时更新,减少等待时间。
(2)减少服务器负载
-
减少 HTTP 请求:页面切换时,只有部分数据需要从服务器加载,而不是整个页面。这可以显著减少服务器的负载和带宽消耗。
(3)便于开发和维护
-
组件化开发:SPA 通常使用现代框架(如 Vue.js 或 React),支持组件化开发,代码更加模块化和可复用。
-
前后端分离:前端和后端可以独立开发,后端只需要提供 API 接口,前端负责页面渲染和交互。
SPA 的缺点
(1)初始加载时间可能较长
-
资源加载:首次加载时,需要加载整个应用的 JavaScript、CSS 和 HTML 模板,这可能导致初始加载时间较长,尤其是在网络环境较差的情况下。
-
优化建议:通过代码分割、懒加载和缓存策略可以缓解这一问题。
(2)SEO 优化困难
-
搜索引擎爬取:传统的 SPA 在首次加载时,页面内容是空的,这可能导致搜索引擎无法正确爬取和索引页面内容。
-
解决方案:使用服务器端渲染(SSR)或静态生成(SSG)可以解决 SEO 问题。
27.怎样理解 Vue 的单向数据流
确保数据的流动方向是明确和可预测的。单向数据流意味着数据只能从父组件流向子组件,而子组件不能直接修改父组件的数据。这种设计使得数据的流向更加清晰,便于维护。
28.Vue3.0 性能提升主要是通过哪几方面体现的
一篇带你搞懂 为什么Vue3比Vue2效率更高!_vue3为什么比vue2快-CSDN博客
静态提升
编译时编译器会发现静态节点,然后进行提升。
vue2只要数据更改会反复渲染静态节点和动态节点,重新创建新的render渲染函数
vue3将静态节点提升后,静态节点就只会创建一次。
预字符串化
处理大量静态内容时。它的主要作用是将静态内容在编译阶段转换为字符串,以减少运行时的计算和处理。
缓存事件处理函数
Vue 3 在编译模板时,会分析模板中的事件绑定,并在编译阶段缓存事件处理函数。这意味着,如果事件处理函数没有变化,Vue 3 将重用缓存的函数,而不是在每次渲染时都重新创建它们。这减少了内存使用,同时也减少了垃圾收集器的工作量
PatchFlag
PatchFlag 是一种位掩码,用于快速判断和跳过不需要更新的节点。在 Vue 2 中,每次更新时都需要进行全量对比,而在 Vue 3 中,只有带有 PatchFlag 标记的元素才会被认为是动态元素,因此只对比带有标记的部分,大大减少了非动态内容的对比消耗 。
29.vue服务端渲染(SSR),解决了哪些问题
Vue服务端渲染(SSR)页面内容由服务器生成,直接返回渲染好的 HTML。
以实现更快的页面加载速度、更好的搜索引擎优化和更好的用户体验。服务端渲染解决了许多SPA
应用程序中存在的问题,例如:
1. SEO(搜索引擎优化)问题:SEO 友好,搜索引擎可直接抓取 HTML。
2. 首屏渲染问题:首次加载时需要下载所有 JavaScript 文件并执行,才能渲染页面,导致首屏加载时间较长(尤其是低性能设备或弱网络环境下)。SSR是服务器直接返回渲染好的 HTML,用户无需等待 JavaScript 下载和执行即可看到内容,提升首屏加载速度。
CSR
CSR 是一种在浏览器完成页面渲染的技术
-
流程:
-
浏览器加载 HTML 文件(通常是一个空容器)。
-
下载并执行 JavaScript 文件。
-
JavaScript 动态生成页面内容并插入 DOM。
-
30.Treeshaking特性是什么,并举例
Tree shaking 是一种通过清除多余代码方式来优化项目打包体积的技术
Tree shaking 无非就是做了两件事:
编译阶段利用 ES6 Module 判断哪些模块已经加载
判断那些模块和变量未被使用或者引用,进而删除对应代码
31.虚拟 DOM
详谈面试题:Vue、React为什么使用虚拟DOM_react和vue使用虚拟dom的原因是 react和vue的颗粒度没那么高-CSDN博客
虚拟 DOM 实现原理
虚拟 DOM是一种用于优化 Web 应用性能的技术,核心思想是通过 JavaScript 对象模拟真实 DOM 结构,通过 高效的差异(Diff)算法 计算出最小化的 DOM 操作,从而减少直接操作真实 DOM 的开销。
虚拟 DOM 的实现原理主要包括以下 3 部分:
- 用 JavaScript 对象模拟真实 DOM 树,对真实 DOM 进行抽象;
- diff 算法 — 比较两棵虚拟 DOM 树的差异;
- pach 算法 — 将两个虚拟 DOM 对象的差异应用到真正的 DOM 树。
虚拟 DOM 的优缺点
1. 优点
-
性能优化:
-
虚拟 DOM 通过减少对真实 DOM 的直接操作,显著提高了 Web 应用的渲染效率。
-
虚拟 DOM 可以将多个 DOM 操作合并为一次更新,减少了浏览器的重绘次数。
-
-
跨平台能力:
-
虚拟 DOM 是与平台无关的抽象层,可以在不同的平台上运行,包括浏览器、移动端和服务器等。更容易地实现跨平台开发。
-
-
简化开发:
-
使得代码更加清晰和可维护,开发者可以更加关注业务逻辑,而不是 DOM 操作细节。
-
2. 缺点
-
增加内存消耗:
-
虚拟 DOM 需要在内存中维护一份 DOM 的副本,这可能会增加内存消耗。在处理大型复杂视图时,可能会导致内存占用较高。
-
-
兼容性问题:
-
在某些旧版本的浏览器中,虚拟 DOM 可能存在兼容性问题。
-
32.Vue 中的 key 有什么作用
key 是 Vue 中 vnode 的唯一标记,通过这个 key, diff 操作可以更准确快速。
Vue可以精确地知道哪些节点是新的,哪些是旧的,哪些需要被移动或删除。
如果没有,Vue 可能会复用组件实例,导致意外的行为。
例如,一个使用v-for渲染的列表中,如果列表的顺序发生变化,而没有设置key,Vue可能会错误地复用现有元素,导致状态混乱。
33.reactive与ref的区别
从定义数据角度对比:
- ref用来定义:基本类型数据
- reactive用来定义对象(或数组)类型数据
从原理角度对比:
- ref通过Object.defineProperty()的get与set来实现响应式(数据劫持)。
- reactive通过使用Proxy来实现响应式(数据劫持), 并通过Reflect操作源对象内部的数据。
从使用角度对比:
- ref定义的数据:操作数据需要.value,读取数据时模板中直接读取不需要.value。
- reactive定义的数据:操作数据与读取数据:均不需要.value。
34.vue的h函数
Vue 的 h
函数用于创建虚拟 DOM 节点,将组件、HTML 元素或文本转换为 VNode
// 基本形式
const vnode = h(type, props, children);
如
h('div', { class: 'box' }, 'Hello');
-
type
(必需):-
可以是 HTML 标签名(如
'div'
)、组件对象(如MyComponent
)或异步组件。
-
-
props
(可选):-
一个对象,包含属性(如
class
、style
)、事件(如onClick
)、DOM 属性(如innerHTML
)等。
-
-
children
(可选):-
子节点,可以是字符串、数组(嵌套的
h
函数)或插槽内容
-
Vue 支持 JSX 语法,JSX 会被 Babel 转换为 h
函数调用:
35.setup函数的俩个参数
Vue 3 的 setup
函数接收两个参数:props
和 context
。props
是响应式对象,包含父组件传递的属性值,不可直接修改,需通过 emit
触发事件通知父组件更新。context
提供上下文信息,包括 attrs
(未声明的属性)、slots
(插槽内容)、emit
(触发事件的方法)和 expose
(暴露组件方法)。例如,在 setup
中通过 props.title
访问属性,通过 context.emit('submit')
触发事件,确保逻辑清晰且符合响应式规范。
36.vue创建路由的方式有哪些
Vue 提供了 vue-router
,这是 Vue.js 的官方路由管理器
安装 vue-router
创建路由配置文件 如 router/index.js
在主文件中引入并使用路由(如 main.js
):
在组件中使用 <router-link>
和 <router-view>
:
37.说一下宏任务和微任务
宏任务:较大的异步任务
-
setTimeout
和setInterval
:基于时间的延迟执行。 -
用户交互事件(如点击、滚动等)。
微任务:较小的异步任务
微任务的执行优先级高于宏任务,会在当前同步代码执行完成后立即执行。
-
Promise
的.then()
、.catch()
和.finally()
。 -
MutationObserver
(用于监听 DOM 变化)。
38.动态路由
动态路由是指在路由路径中包含动态参数的路由,从而实现灵活的页面导航。动态路由通常用于构建如用户详情页,其中 URL 的一部分是动态变化的,以 :
开头来定义。
如何获取动态参数?
vue2中:this.$route.params
vue3中:useRoute
39.说下Vue2的Mixins
mixins
可以将一些可重用的功能或逻辑提取到一个单独的对象中,并在多个组件中共享这些功能。
mixins: [myMixin], // 引入 mixin
五、微信小程序
1.Rpx
(1) Rpx是微信小程序中响应单位
(2) rpx是微信小程序独有的、解决屏幕自适应的尺寸单位
(3) 可以根据屏幕宽度进行自适应,不论大小屏幕,规定屏幕宽为750rpx
2.小程序和vue区别
(1) 事件定义区别:vue通过@绑定事件,小程序通过bind
(2) 事件函数传值:vue传值直接写在函数括号中,微信小程序传值需要用data-自定义名字={{需要传递的
值}}
(3) 关键字引用:vue中属性名前面加 “:” 或者 v-bind,微信小程序中只需要属性值加“{{}}”包起来就行
(4) 指令使用方式:vue中通过v-使用,小程序中通过wx:使用
3.WXSS和CSS的异同
- 新增了rpx尺寸单位,css中需要手动进行像素单位换算,例如rem
- WXSS支持新的尺寸rpx,在不同大小的屏幕上小程序会自动进行换算
- 提供了全局样式和局部样式,项目根目录中的app.wxss会作用于所有小程序页面,局部页面的.wxss样式仅对当前页面生效
- WXSS仅支持部分css选择器:
- ① 类选择器,id选择器
- ② 元素选择器
- ③ 并集选择器,后代选择器
- ④ ::after和::before等伪类选择器
4.微信小程序有哪些传值(传递数据)方法
(1) 使用全局变量传递数据
(2) 使用本地存储数据传递
(3) 使用路由传递数据
5.Bindtap和catchtap区别
bindtap :子元素使用bindtap绑定事件后,执行的时候,会冒泡到父元素(触发父元素上绑定的
bingtap事件)
catchtap :不会冒泡到父元素上,阻止事件冒泡
6.wx.navigateTo(),wx.redirectTo(),wx.switchTab(),wx.navigateBack(),wx.reLaunch()的区别?
(1) wx.navigateTo(Object):保留当前页面,跳转到应用内的某个页面。但是不能跳到 tabbar 页面。使用wx.navigateBack 可以返回到原页面。小程序中页面栈最多十层
(2) Wx.navigateBack():关闭当前页面,返回上一页面或多级页面。可通过 getCurrentPages 获取当前的页面栈,决定需要返回几层
(3) wx.redirectTo():关闭当前页面,跳转到应用内的某个页面。但是不允许跳转到 tabbar 页面
(4) wx.switchTab():跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面
(5) wx.reLaunch():关闭所有页面,打开到应用内的某个页面,可以跳转到tarBar的页面
7.小程序的生命周期
微信小程序的生命周期分为应用生命周期和页面生命周期,它们分别用于管理小程序整体和单个页面的运行状态。以下是详细的生命周期函数及其作用:
1. 应用生命周期(App 级)
应用生命周期函数影响整个小程序,定义在 app.js
中,主要用于监听小程序的启动、前后台切换、错误处理等。
生命周期函数 | 触发时机 | 作用 |
---|---|---|
onLaunch(options) | 小程序初始化时触发(只触发一次) | 适合进行全局初始化,如登录、获取系统信息等。 |
onShow(options) | 小程序进入前台时触发 | 适合恢复应用状态、检查新消息。 |
onHide() | 小程序进入后台时触发 | 适合存储数据、暂停操作。 |
onError(error) | 小程序发生 JS 错误时触发 | 适合上报错误日志。 |
onPageNotFound(options) | 访问不存在的页面时触发 | 适合跳转到默认页面。 |
onUnhandledRejection(res) | Promise 被 reject 但没有 catch 时触发 | 适合全局错误处理。 |
onThemeChange(res) | 用户切换系统主题时触发 | 适合适配深色模式。 |
2. 页面生命周期(Page 级)
页面生命周期函数影响单个页面,定义在页面的 page.js
文件中,主要用于处理页面的加载、显示、隐藏、卸载等。
生命周期函数 | 触发时机 | 作用 |
---|---|---|
onLoad(options) | 页面创建时触发(只触发一次) | 适合获取 URL 参数、初始化数据。 |
onShow() | 页面显示时触发 | 适合刷新数据、监听事件。 |
onReady() | 页面首次渲染完成后触发(只触发一次) | 适合执行 DOM 相关操作。 |
onHide() | 页面被隐藏时触发(如跳转到其他页面) | 适合存储状态、暂停操作。 |
onUnload() | 页面被卸载(关闭)时触发 | 适合释放资源、存储数据。 |
onPullDownRefresh() | 用户下拉刷新时触发 | 适合重新获取数据。 |
onReachBottom() | 页面滚动到底部时触发 | 适合加载更多数据。 |
onShareAppMessage() | 用户点击转发时触发 | 适合自定义分享内容。 |
onPageScroll(res) | 页面滚动时触发 | 适合监听滚动位置。 |
onResize(res) | 页面尺寸变化时触发 | 适合适配屏幕变化。 |
onTabItemTap(item) | 用户点击 tabbar 时触发 | 适合处理 tabbar 切换。 |
3. 生命周期触发顺序
-
小程序启动:
-
onLaunch()
(小程序初始化)。 -
onShow()
(小程序进入前台)。 -
onLoad()
(页面加载)。 -
onReady()
(页面渲染完成)。 -
onShow()
(如果是从后台返回前台)。
-
-
小程序进入后台:
-
onHide()
。
-
-
小程序退出:
-
如果被系统强制关闭,可能不会触发
onHide()
或onUnload()
。 -
建议在
onHide()
中保存数据,防止数据丢失。
-
六、webpack篇
1.谈谈你对Webpack的理解
Webpack 是一个 静态模块打包器,可项目中的所有资源皆为模块,通过分析模块间的依赖关系,在其内部递归构建出一个依赖关系图,然后将这些模块打包成一个或多bundle 。最终编绎输出模块为 HTML、JavaScript、CSS 以及各种静态文件(图片、字体等)
通过webpack的Loader机制,可以编译转换诸如.less,.vue,.jsx这类在浏览器无法识别的格式文件,ES6的语法转成向后兼容的 JavaScript 代码,提高开发效率。
通过webpack的Plugin机制,可以进一步实现诸如按需加载,代码压缩等一系列功能,帮助我们进一步提高工程效率。
核心能力:
打包压缩:变量名函数名全部被替换,空格换行也没了。这样做可以有效的减少代码的体积,从而减少网络的传输
文件指纹:打包结果中,文件名后方都带上了一串数字字母,他的本质是hash值前几位,会根据源代码的内容不同而不同。为了解决缓存问题,请求一次后浏览器会将请求的结果缓存。如果没有文件指纹,文件变动了,浏览器不知道依然会从缓存中去拿。
开发服务器:
在内存中打包,把打包结果直接给浏览器,当改动源码时,webpack会监听源码目录,一旦改变就会重新打包,并刷新浏览器页面,浏览器刷新后就会重新请求开发服务器。开发服务器重新拿打包结果,并响应给浏览器。
编译过程
2.模块分析
一个一个读取模块依赖,并记录加载,如果再次读到已被记录的模块,则不会再次加载
连小白都看得懂的Webpack教程_webpack 菜鸟教程-CSDN博客
2.webpack的热更新是如何做到的
热更新的核心就是客户端从服务端拉去更新后的文件,准确的说是 chunk diff (chunk 需要更新的部
分),实际上webpack-dev-server与浏览器之间维护了一个websocket,当本地资源发生变化时,
webpack-dev-server会向浏览器推送更新,并带上构建时的hash,让客户端与上一次资源进行对比。客户端对比出差异后会向webpack-dev-server发起 Ajax 请求来获取更改内容(文件列表、hash),这样客户端就可以再借助这些信息继续向webpack-dev-server发起 jsonp 请求获取该chunk的增量更新。
3.如何提高Webpack构建速度
使用Webpack 5的持久化缓存可以显著减少构建时间,因为缓存可以在多次构建间复用。然后,优化loader时,可以通过exclude排除node_modules,减少不必要的文件处理。
可能还需要提到使用speed-measure-webpack-plugin插件来分析各个阶段的耗时,找出瓶颈。还有生产环境下的配置优化,比如避免sourceMap,使用TerserPlugin多线程压缩等。
4.大批量数据渲染
-
懒加载:如果数据是列表形式,可以采用懒加载。比如,用户滚动到页面底部时,再加载下一批数据。这样用户一开始不需要等待所有数据加载完成,体验会更好。
-
虚拟滚动:对于超长列表,可以用虚拟滚动技术。比如,只渲染当前可视区域的数据,其他数据暂不渲染,当用户滚动时动态更新。这样可以大大减少 DOM 元素的数量,提升性能。
-
计算可视区域: 根据容器的高度、滚动位置和每个数据项的高度,计算出当前可视区域的起始索引和结束索引。 创建占位元素: 为了保持滚动条的正确性,需要在容器中添加一个占位元素,其高度等于所有数据项的总高度。 动态渲染数据: 只渲染当前可视区域内的数据项。当用户滚动时,更新可视区域的索引范围,并重新渲染数据。 定位列表项: 使用 CSS 的 transform 属性将渲染后的列表项定位到正确的位置。
-
骨架屏:在数据加载过程中,可以先显示一个骨架屏,让用户知道页面正在加载,提升用户体验。
-
分页处理:最常用的方式是分页。比如,后端每次只返回一部分数据(比如每页10条),前端每次只渲染当前页的数据。这样可以减少单次加载的数据量,提升页面性能。