前端面试题汇总
本文将不定期持续更新,欢迎您收藏本站!😘
由于本文篇幅较长,您可以点击 ctrl+F 直接搜索关键字。
注意:部分答案来源于网络,如发现有错误,请联系我修正,谢谢!
HTTP
从输入url到页面加载发生了什么
大致过程如下:
DNS解析:将域名解析成IP地址;TCP连接:TCP 三次握手;- 浏览器向服务器发送
HTTP请求; - 服务器处理
HTTP请求,并返回给浏览器; - 浏览器解析并渲染页面;
- 关闭连接:TCP 四次挥手;
HTTP的状态码及含义
常见的http headers
HTTP缓存有哪几种
HTTP 缓存可分为两大类,分别是:强制缓存和协商缓存。
强制缓存在缓存数据未生效的情况下,是不需要再和服务器发生交互的;而协商缓存,顾名思义是需要跟服务器进行比较判断是否可以使用缓存。
注意:强制缓存的优先级高于协商缓存的
强制缓存:
强制缓存分两种情况,分别是 Expires 和 Cache-Control。
Expires:它的值是服务器告诉浏览器的缓存过期时间的,是一个绝对时间,顾名思义是下次请求时,如果当前距上次请求时间还未超过过期时间时,就直接使用缓存数据。但是存在一些问题:- 客户端和服务器的时间不一致会出现问题;
- 在缓存未生效前,获取不到修改后的资源;
Cache-Control:它是设置相对时间,它可以解决Expires出现的问题。
Cache-Control 有以下可选值:
no-cache:不直接使用缓存,根据新鲜度来使用缓存;no-store:不使用缓存,每次都是请求下载新资源;max-age:设置缓存存储的最大周期,超过这个时间就被认为过期;public / private:是否只能被单个用户使用,默认值为private;must-revalidate:每次访问需要缓存校验。
注意:Cache-Control 优先级高于 Expires。
协商缓存:
它是服务器端缓存策略,相关属性有:ETag / if-Not-Match、Last-Modified / If-Modified-Since。
执行流程如下:
- 当浏览器第一次向服务器发送请求时,会在响应头中返回协商缓存的头属性:
ETag和Last-Modified,其中ETag返回的是一个hash值,Last-Modified返回的是GMT格式的最后修改时间。 - 浏览器在第二次发送请求的时候,会在请求头中带上与
ETag对应的if-Not-Match,其值就是响应头中返回的ETag的值,再带上Last-Modified对应的If-Modified-Since。服务器在接收到这两个参数后会做比较,如果返回的是304状态码,则说明请求的资源没有修改,浏览器可以直接在缓存中取数据,否则,服务器会直接返回数据。
它们的优先级是:Cache-Control > Expires > ETag > Last-Modified。
我们先来看看三种刷新:
- 正常操作:地址栏输入 url,跳转链接,前进后退等;
- 手动刷新:F5,右键刷新,刷新按钮;
- 强制刷新:ctrl + F5;
使用不同的刷新操作,会有不同的缓存策略:
- 正常操作:强制缓存有效,协商缓存有效;
- 手动刷新:强制缓存失效,协商缓存有效;
- 强制刷新:强制缓存失效,协商缓存失效;
Cookie、Session、LocalStorage之间的区别
GET和POST的区别
GET请求一般去获取数据,POST请求一般发送数据到后台使用;GET请求的参数在url上可见,而POST请求的参数放在Request body中;GET请求参数的长度有限制,POST请求没有长度限制;GET请求刷新浏览器或回退没有影响,POST请求回退会重新提交数据;GET请求可被缓存,POST请求不会;GET请求保留在浏览器历史记录里,POST请求不会;GET请求可被收藏为书签,POST请求不能;GET请求只能进行url编码,POST请求支持多种编码方式;GET请求只需要一个报文,POST请求需要两个及以上;
其实这两种请求最本质的区别就是语义不同,GET 请求是获取数据,而 POST 请求是提交数据
HTTP与HTTPS的区别
http是以http://开头,https是以https://开头;http默认使用80端口,而https默认使用443端口;http是超文本传输协议,信息采用明文传输,而https则是具有安全性SSL加密传输协议;https协议需要到证书颁发机构CA申请证书,大多数情况下需要一定费用;
描述一下TCP的三次握手和四次挥手
减少http请求的方法
- 使用
CSS雪碧图; base64编码图片;- 缩小
JS和CSS文件; - 合并
JS和CSS文件; - 图片地图(Image Maps);
- 使用浏览器 缓存机制。
http1与http2的区别
- 新的二进制格式(Binary Format),
HTTP1.x的解析是基于文本。基于文本协议的格式解析存在天然缺陷,文本的表现形式有多样性,要做到健壮性考虑的场景必然很多,二进制则不同,只认0和1的组合。基于这种考虑HTTP2.0的协议解析决定采用二进制格式,实现方便且健壮。 - 多路复用(MultiPlexing),即连接共享,即每一个
request都是是用作连接共享机制的。一个request对应一个id,这样一个连接上可以有多个request,每个连接的request可以随机的混杂在一起,接收方可以根据request的id将request再归属到各自不同的服务端请求里面。 header压缩,HTTP1.x的header带有大量信息,而且每次都要重复发送,HTTP2.0使用encoder来减少需要传输的header大小,通讯双方各自cache一份header fields表,既避免了重复header的传输,又减小了需要传输的大小。- 服务端推送(server push),同
SPDY一样,HTTP2.0也具有server push功能。
https对称加密与非对称加密是什么
- 对称加密:发送方和接收方需要持有同一把密钥,在发生消息和接收消息均使用该密钥。相对于非对称加密来说,对称加密具有更高的加解密速度,但是双方都需要事先知道密钥。密钥在传输过程中可能会被窃取,因此对于安全性而言,对称加密没有非对称加密安全性高;
- 非对称加密:接收方在发生消息前需要事先生成公钥和私钥,然后将公钥发送给发送方。发送方收到公钥后,将待发送数据用公钥加密然后发送给接收方,接收方收到数据后用私钥解密。其中公钥负责加密、私钥负责解密,在数据传输过程中,如果被窃取,由于攻击者没有私钥也无法进行破解。非对称加密的加解密速度要低于对称加密,但是安全性更高;
如何劫持https的请求
HTML
如何理解HTML语义化
HTML 语义化就是使用正确的标签做正确的事;比如段落就用 p 标签,页眉就用 header 标签,页脚用 footer 标签,导航用 nav 标签,文章就用 article 标签,视频用 video 标签等等。
HTML 语义化的好处有:
- 易于用户阅读:在没有
CSS情况下,页面也能够更好的呈现内容结构与代码结构; - 便于团队的开发和维护:更具有可读性,让代码更好的维护;
- 有利于
SEO:搜索引擎的爬虫依赖于标签来确定上下文和各个关键字的权重; - 利于其他设备的解析:如屏幕阅读器、盲人阅读器,提高可访问性。
meta viewport是做什么用的,怎么写
1 | <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"> |
| 参数 | 含义 |
|---|---|
| width | 设置 layout viewport 的宽度,为一个正整数,或字符串”device-width” |
| initial-scale | 设置页面的初始缩放值,为一个数字,可以带小数 |
| minimum-scale | 允许用户的最小缩放值,为一个数字,可以带小数 |
| maximum-scale | 允许用户的最大缩放值,为一个数字,可以带小数 |
| height | 设置 layout viewport 的高度,这个属性对我们并不重要(很少使用) |
| user-scalable | 是否允许用户进行缩放 |
1 | <!DOCTYPE html> H5标准声明,使用 HTML5 doctype,不区分大小写 |
img标签中的alt和title有什么区别
alt是当图片加载失败时,显示在网页上替代图片的文字;title是鼠标放在图片上时显示的文字,来更加清楚的表达其目的;
注意:alt 只适用于 img 标签,而 title 适用于很多标签。
你用过哪些HTML5标签
HTML5有哪些新特性?废除了哪些元素?如何让低版本IE支持HTML5新标签?
新特性:
- 语义:新增加了
<section>、<article>、<nav>、<header>、<footer>等标签; - 连通性:增加
Web Sockets、Server-sent events特性,帮助我们实现服务器将数据推送到客户端的功能; - 离线 & 存储:对本地离线存储的更好的支持;
localStorage长期存储数据,浏览器关闭后数据不丢失;sessionStorage的数据在浏览器关闭后自动删除; - 多媒体:
<audio>和<video>元素嵌入并支持新的多媒体内容的操作; - 2D/3D 绘图 & 效果:增加用于绘制图像的
canvas,SVG矢量图像格式; - 性能 & 集成:
HTML5会通过XMLHttpRequest2等技术,帮助您的Web应用和网站在多样化的环境中更快速的工作; - 设备访问 Device Access:能够处理各种输入和输出设备。
废除的元素:
- 表现元素:
basefont、big、center、font、s、strike、tt、u; - 部分浏览器支持的元素:
applet、bgsound、blink、marquee; - 对可用性产生负面影响的元素:
frameset、frame、noframes,在html5中不支持frame框架,只支持iframe框架。
让低版本的 IE 支持 HTML5 新标签:
使用 html5shiv 可以解决 IE 低版本不兼容的问题,只需要在 head 中加入当版本低于 IE9 时,浏览器会加载 html5.js 脚本,使得支持 HTML5 的新功能,也可以将脚本文件下载到本地。
1 | <head> |
H5是什么
首先 H5 != HTML5,其次 H5 是指在手机这类无法播放 Flash 的移动端上呈现的,可以达到 Flash 效果的网页,也可称移动端 PPT。
@import与link的区别
@import是CSS提供的语法规则,只有导入样式表的作用;link是HTML的标签,不仅可以加载CSS,还可以定义RSS、rel连接属性等;- 页面被加载时,
@import引入的CSS将在页面加载完毕后被加载;link标签引入的CSS被同时加载; @import在IE5+才能被识别;link不存在兼容问题;@import不支持使用JS控制DOM改变样式;而link支持。
src和href有什么区别
src表示的是对资源的引用,会替换当前内容,常见在 img、iframe、script 标签上使用;href超文本引用,是用于在当前文档和引用资源之间确立联系,常见在 a、link 标签上使用;
注意:浏览器在解析 src 时会停下来等到 src 的内容加载完毕后再加载后续内容;而 href 在加载的时候不会停止对后续内容的处理。
对浏览器内核的理解及常见的浏览器内核有哪些
浏览器的内核分成两部分:渲染引擎 和 JS引擎。
- 渲染引擎:负责取得网页的内容(HTML、XML、图像等)、整理讯息(例如加入 CSS 等),以及计算网页的显示方式,然后会输出至显示器或打印机。
- JS 引擎:解析
JavaScript语言,执行JavaScript语言来实现网页的动态效果。
常见的浏览器内核如下:
- Trident 内核(又称 MSHTML):IE、猎豹安全浏览器、360 安全浏览器、搜狗浏览器、百度浏览器、UC 浏览器等等;
- Gecko 内核:Netscape6 及以上版本、FireFox 等;
- Webkit 内核:Chrome、Safari 等;
- Presto 内核(现为 Blink):Opera7 及以上。
什么是DOCTYPE
<!DOCTYPE> 必须声明在文档中的最前面的位置。
<!DOCTYPE> 声明不是一个 HTML 标签,它是指示 web 浏览器关于页面使用哪个 HTML 版本进行编写的指令。
<!DOCTYPE> 不存在或者格式不正确会导致文档以兼容模式呈现。
注意:总是给您的 HTML 文档添加 <!DOCTYPE> 声明,确保浏览器能够预先知道文档类型。
HTML5为什么只需要写<!DOCTYPE html>
- HTML5 不基于 SGML,因此不需要对 DTD 进行引用,但是需要 DOCTYPE 来规范浏览器的行为;
- HTML4.01 基于 SGML,需要对 DTD 进行引用才能告知浏览器文档所使用的文档类型;
HTML全局属性有哪些
iframe有哪些缺点
iframe会阻塞主页面的onload事件;- 搜索引擎和检索程序无法解读这种页面,不利于
SEO; iframe和主页面共享连接池,而浏览器对相同域的连接有限制,会影响页面的并行加载;- 会产生很多页面,不易管理;
CSS
css hack是什么
两种盒模型
盒模型分为W3C的标准模型和IE模型
盒模型又称为框模型,包含了元素内容(content)、内边距(padding)、外边距(margin)、边框(border)
如图:
W3C 的标准模型:width/height 属性指 content。
IE 模型:width/height 属性由 content + padding + border 组成。
这两种模型的区别就是计算的宽度和高度不同。
通过 CSS3 新增的属性 box-sizing:content-box | border-box; 分别设置盒模型为标准模型(content-box)和 IE 模型(border-box)
W3C 的标准模型:
1 | <div class="content-box"></div> |
1 | .content-box { |
其中:width = 100px
IE 模型:
1 | <div class="border-box"></div> |
1 | .border-box { |
其中:width = content + 2padding + 2border = 100px
相对比较而言:border-box 更好用!!!
JS 如何设置获取盒模型对应的宽和高呢?
1 | dom.style.width / height; // 设置获取的是内联样式 |
为什么要初始化CSS样式
因为浏览器的兼容问题,不同浏览器的部分标签默认值都是不同的,如果没有对 CSS 样式初始化会出现各个浏览器之间的页面显示差异。
对 CSS 样式初始化后会对 SEO 有一定的影响,所以力求影响最小的情况下进行初始化。
最简单也最不建议初始化的方式:
1 | * { |
可以使用 normalize.css 进行 CSS 初始化。
以下是淘宝的样式初始化代码:
1 | body,h1,h2,h3,h4,h5,h6,hr,p,blockquote,dl,dt,dd,ul,ol,li,pre,form,fieldset,legend |
块级元素与行内元素分别有哪些以及各有什么特点
行内元素:
一个行内元素只占据它对应标签的边框所包含的空间,行内元素前后不会产生换行,一系列的行内元素都在一行显示,直到该行排满为止再另起一行。
行内元素有:a、img、span、button、input、textarea、label、em、kbd、br、b、i、tt 等等。
特点:
- 和其他元素都在同一行上;
- 宽度(width)、高度(height)、内边距的
top / bottom(padding-top / padding-bottom)和外边距的top / bottom(margin-top / margin-bottom)都不可改变,但是padding、margin的left和right是可以设置的,line-height也是有效的; - 宽度就是它的文字或图片的宽度,是不可改变的;
- 行内元素只能容纳文本或者其他行内元素,不能容纳块级元素;
- 行内元素会在一条直线上排列,都是同一行的,水平方向排列。
块级元素:
块级元素占据其父元素(容器)的整个空间,因此创建了一个“块”。通常浏览器会在块级元素前后另起一个新行。
块级元素有:div、p、h1 ~ h6、hr、ul、ol、li、dd、dl、table 等等。
特点:
- 独占一行,每一个块级元素都会从新的一行重新开始;
- 宽度(width)、高度(height)、内边距(padding)和外边距(margin)都可设置;
- 如果宽度没有设置,则默认宽度为容器的
100%; - 块级元素可以容纳行内元素和其他块级元素;
- 块级元素各占据一行,垂直方向排列。
position有哪些常用的值
static:static 是 position 属性的默认值,如果省略了 position 属性,浏览器就认为该元素为 static 定位。
浏览器会按照源码的顺序,决定每个元素的位置,这称为 “正常的页面流“(normal flow)。每个块级元素占据自己的区块(block),元素与元素之间不产生重叠,这个位置就是元素的默认位置。
static 定位所导致的元素位置,是浏览器自主决定的,所以这时 top、bottom、left、right 这四个属性无效,并且 z-index 设置也无效。
relative:relative 表示相对定位,是默认参照父级的原始点为原始点来定位的,若无父元素则按照上一个元素的底部为原始点进行定位。
- 相对定位不会影响元素本身的特性;
- 不会使元素脱落文档流;
- 没有定位偏移量时对元素无影响;
top、bottom、left、right、z-index属性有效。
absolute:absolute 表示绝对定位,相对于 static 定位以外的第一个父元素进行定位。
- 使元素完全脱离文档流;
- 可以改变行内元素的特性,即可以设置宽高;
- 在未设置宽度时,宽度由内容撑开;
- 相对于最近的一个有定位的父元素偏移,若父元素没有定位则逐层向上找直至
body为止; top、bottom、left、right、z-index属性有效。
fixed:fixed 表示固定定位,相对于浏览器窗口进行定位。即定位基点是浏览器窗口。这会导致元素的位置不随页面滚动而变化,就好像固定在网页上一样。
搭配 top、bottom、left、right 这四个属性一起使用,表示元素的初始位置是基于视口计算的,否则初始位置就是元素的默认位置。
CSS中伪类与伪元素的区别
如何水平居中
如何垂直居中
flex怎么用,常用属性有哪些
grid布局怎么用
display:none; 、visibility:hidden; 、opacity:0; 有什么区别
display:none;:
- 隐藏对应的元素,浏览器不会渲染,在文档布局中不占据空间;
- 无法进行
DOM事件监听; - 会引起重排,性能较差;
- 不会被子元素继承。
visibility:hideen;:
- 隐藏对应的元素,浏览器会渲染,在文档布局中占据原来的空间;
- 无法进行
DOM事件监听; - 只会引起重绘,性能较高;
- 会被子元素继承,子元素可以设置
visibility: visible;来进行显示。
opacity:0;:
- 将透明度为
100%,元素被隐藏了,在文档布局中占据原来的空间; - 可以进行
DOM事件监听; - 提升为合成层,不会触发重绘,性能较高;
- 会被子元素继承,但是子元素设置
opacity: 1;无效。
使用 display:none; 属性后,HTML 元素(对象)的宽度、高度等各种属性值都将丢失;使用 visibility:hideen; 属性后,HTML 元素(对象)仅仅是在视觉上看不见(完全透明),而它所占据的空间位置仍然存在;而使用 opacity:0; 属性后,也仅仅是将透明度设置成了 100%,以致于在视觉上完全看不见。
BFC是什么,举例回答
CSS选择器的优先级
- 越具体优先级越高;
- 写在后面的覆盖前面的;
!important,最高,但是要少用!!important> 行内样式 >id>class>tag> 通配符 > 继承 > 浏览器默认属性。
CSS哪些属性可以继承
继承就是指子节点默认使用父节点的样式属性。
可继承的属性大概有颜色、文字、字体间距、行高、对齐方式、列表的样式。
- 所有元素可继承:元素可见性(visibility)、光标属性(cursor);
- 内联元素可继承:
letter-spacing、word-spacing、white-space、line-height、color、font、font-family、font-size、font-style、font-variant、font-weight、text-decoration、text-transform、direction; - 块状元素可继承:
text-indent、text-align; - 列表元素可继承:
list-style、list-style-type、list-style-position、list-style-image。
如何清除浮动
em与rem
px、em、rem区别
px:表示像素,是相对于屏幕像素,相对长度单位;
em:相对长度单位,这个单位表示元素的
font-size的计算值。它会继承父级元素的字体大小,因此并不是一个固定的值;1
2
3<div class="parent">
<div class="son"></div>
</div>1
2
3
4
5
6
7
8
9.parent {
background-color: red;
font-size: 20px;
height: 2em;
}
.son {
background-color: blue;
height: 1em;
}因此,
parent这个盒子高度为40px,son这个盒子高度为20px。rem:这个单位代表根元素的
font-size大小(例如<html>元素的font-size)。当用在根元素的font-size上面时 ,它代表了它的初始值。例如:设置html { font-size: 20px }时,其他元素1rem = 20px,5rem = 100px;
如下代码可以进行适配:
1 | document.documentElement.style.fontSize = document.documentElement.clientWidth / 37.5 + 'px' |
CSS3有哪些新特性
- 新增各种 css 选择器,例如:
:root、:last-child、:first-of-type、:last-of-type等等; - 三个动画相关特性:过渡(transition)、2D或3D转换(transform)、动画(animation);
- 三个边框属性:圆角边框(border-radius)、添加阴影(box-shadow)、使用图片来绘制边框(border-image);
- 背景属性:确定背景画区(background-clip)、确定背景的位置(background-origin)、调整背景图片的大小(background-size);
- 文字效果:强制换行(word-wrap)、当文本溢出包含它的元素该如何显示(text-overflow)、文本阴影(text-shadow)、规定添加到文本的修饰(text-decoration);
- 渐变:线性渐变(linear-gradient)、径向渐变(radial-gradient);
- 多列布局;
- 媒体查询:
@media; - 字体:
@font-face。
去除inline-block元素间间隙的方法
如何适配各种移动设备
如何添加代码使得图片宽度为300px
1 | <img src="#.png" style="width:500px!important;"> |
使用 CSS 有如下三种方法:
1 | // 1. 最简单的就是直接在后面添加宽度并设置 !important 来覆盖掉 |
使用 JS 的方法:
1 | // 使用 setAttribute 来属性 |
用纯CSS画一个三角形
1 | .triangle { |
用纯CSS画一个六边形
方法一
1
<div class="hexagon"></div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26.hexagon {
position: relative;
width: 100px;
height: 173.2px;
background-color: red;
margin: 0 auto;
}
.hexagon::before,
.hexagon::after {
content: "";
position: absolute;
display: block;
top: 0;
width: 0;
height: 0;
border-top: 86.6px solid transparent;
border-bottom: 86.6px solid transparent;
}
.hexagon::before {
left: -50px;
border-right: 50px solid red;
}
.hexagon::after {
right: -50px;
border-left: 50px solid red;
}方法二
1
<div class="hexagon"></div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26.hexagon {
position: relative;
width: 100px;
height: 173.2px;
background-color: red;
margin: 0 auto;
}
.hexagon::before,
.hexagon::after {
content: "";
position: absolute;
display: block;
top: 0;
left: 0;
width: 100px;
height: 173.2px;
box-sizing: border-box;
}
.hexagon::before {
background-color: red;
transform: rotate(60deg)
}
.hexagon::after {
background-color: red;
transform: rotate(-60deg)
}
width:auto;和width:100%;的区别是什么
首先它们都是由父级元素所决定的,其次有以下区别:
width:100%;:会使元素的宽度等于父元素的宽度,子元素增加 padding,会使得元素超过父元素的边界;width:auto;:会使元素撑满整个父元素,margin、border、padding、content 区域会自动分配水平空间;
什么是优雅降级和渐进增强
优雅降级:一开始就构建完整的功能,然后再针对低版本浏览器进行兼容。
渐进增强:针对低版本浏览器进行构建页面,保证最基本的功能,然后再针对高级浏览器进行效果、交互等改进和追加功能达到更好的用户体验。
1 | // 渐进增强写法 |
line-height是如何继承的
分如下三种情况:
- 具体的数值(例如:10px):继承该值,如果父元素
line-height: 30px;,则子元素line-height: 30px;; - 比例(例如:1.5):继承该比例,如果父元素
line-height: 2;,且子元素的font-size: 15px;,那么子元素的line-height: 30px;; - 百分比(例如:200%):继承计算出来的值,如果父元素
font-size: 30px; line-height: 200%;,那么子元素line-height: 60px;。
怎么画一条0.5px的线
文本省略有哪些方案
300ms延迟解决方案
设置
meta:1
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no">
使用 fastclick.js:
1
2
3
4
5if ('addEventListener' in document) {
document.addEventListener('DOMContentLoaded', function() {
FastClick.attach(document.body);
}, false);
}css 设置
touch-action:1
2
3* {
touch-action: manipulation;
}
什么是重绘和重排
JavaScript
JS的基础数据类型有哪些
JS中null是对象吗
1 | typeof null // "object" |
虽然上面代码会输出 object,但这是 JS 的一个悠久的 bug。在 JS 最初版本中使用的是 32 位系统,当时为了性能方面的考虑而使用低位存储变量的类型信息,000 开头代表是对象,然而 null 表示为全零,所以将它错误的判断为 object。
export与export default的区别
- 相同点:它们均可用于导出常量、函数、文件、模块等等。
- 不同点:
- 在一个文件或模块中,
export、import可以有多个,但export default仅能有一个; - 通过
export方式导出,在import时导入时需要加{ }; - 通过
export default,在import时导入时不需要加{ }; - 使用
export default命令,为模块指定默认输出,不需要知道加载模块的变量名。
- 在一个文件或模块中,
import与require的区别
ES6语法有哪些,分别怎么用
new的执行过程
- 创建一个空对象;
- 将构造函数的
prototype属性赋值给新对象的__proto__属性,并将构造函数的this指向新对象; - 执行构造函数中的代码(为这个新对象添加属性);
- 将新对象返回;
1 | function Student(name) { |
异常捕获
call、apply、bind区别
call
call()方法使用一个指定的this值和单独给出的一个或多个参数来调用一个函数。1
fun.call(thisArg, arg1, arg2, ...)
apply
apply()方法调用一个具有给定this值的函数,以及作为一个数组(或类似数组对象)提供的参数。当不确定参数的个数时,就可以使用apply。1
func.apply(thisArg, [argsArray])
bind
bind()方法会返回一个新的函数,在bind()被调用时,这个新函数会call原来的函数,新函数的this被bind的第一个参数指定,其余的参数将作为新函数的参数供调用时使用。1
function.bind(thisArg[,arg1[,arg2[, ...]]])
总结
其实 apply 和 call 基本类似,他们的区别只是传入的参数不同。call 方法接受的是若干个参数列表,而 apply 接收的是一个包含多个参数的数组。
bind 和 call、apply 方法作用是一致的,只是该方法会返回一个新函数,并且我们必须要手动去调用。
什么是JSONP
它的基本思想是,网页通过添加一个 <script> 元素,向服务器请求 JSON 数据,这种做法不受同源政策限制;服务器收到请求后,将数据放在一个指定名字的回调函数里传回来。
请求方:xxx.com 的前端程序员(浏览器)
响应方:yyy.com 的后端程序员(服务器)
- 请求方创建
script,src指向响应方,同时传一个查询参数?callback=xxx - 响应方根据查询参数
callback,构造形如这样的响应:
1. xxx.call(undefined,’需要的数据’)
2. xxx(‘需要的数据’) - 浏览器接收到响应,就会执行 xxx.call(undefined,’需要的数据’)
- 那请求方就知道了所需要的数据了
为什么不支持POST?
JSONP是通过动态创建script的;- 动态创建
script时只能用GET,没法用POST;
代码实现 zhouwanwen.com:8001 和 jack.com:8002 之间的 JSONP 请求:Github - nodejs-demo-1
全局函数eval()有什么作用
eval() 函数会将传入的字符串当做 JavaScript 代码进行执行。
eval() 是全局对象的一个函数属性
- 如果
eval()的参数是一个字符串,并且该字符串表示的是表达式,那么eval()会对表达式进行求值;如果参数表示一个或多个 JavaScript 语句,那么eval()就会执行这些语句。 - 如果
eval()的参数不是字符串,eval()会将参数原封不动地返回。
为什么0.1+0.2!==0.3
1 | 0.1 + 0.2 // 0.30000000000000004 |
因为 JavaScript 存储数值采用双精度浮点数,会出现精度丢失的问题。
1 | 0.100000000000000000000002 === 0.1 // true |
如何使得 0.1+0.2 === 0.3 呢?
1 | parseFloat((0.1 + 0.2).toFixed(10)) === 0.3 // true |
==、=== 与 Object.is()
==:相等运算符,会在比较时进行类型转换;===:严格运算符:比较时不进行隐式转换,类型不同则返回false;Object.is():该方法判断两个值是否为同一个值,返回true / false。它不会强制转换两边的值;
对于
string、number等基础类型,是有区别的:- 不同类型:
==:转换成同一类型后的值看值是否相等;===:如果类型不同,结果就不等;
- 相同类型:直接进行值比较;
- 不同类型:
对于
Array、Object等高级类型,是没有区别的;对于基础类型与高级类型,是有区别的:
===:类型不同,结果不等;==:将高级类型转化为基础类型,进行值比较。
Object.is() 方法如果满足以下条件则两个值相等:
- 都是
undefined; - 都是
null; - 都是
true或false; - 都是相同长度的字符串且相同字符按相同顺序排列;
- 都是相同对象(意味着每个对象有同一个引用);
- 都是数字且都是
+0;都是-0;都是NaN;或都是非零而且非NaN且为同一个值;
1 | Object.is('hello','hello') // true |
扩展:
1 | let obj = { |
什么是原型
什么是闭包
什么是CORS,什么是跨域
typeof与instanceof区别
typeof:typeof 可用于基本数据类型的类型判断,例如:number、string、boolean、function、undefined、symbol 等,返回值都是小写的字符串。
1 | console.log(typeof undefined) // undefined |
instanceof:instanceof 是判断变量是否为某个对象的实例,返回值为 true 或 false。
1 | var arr = [] |
区别:
typeof用于基本数据类型的类型判断,无法判断对象的具体类型(除function);instanceof可以用来区分数组、对象,不能用来判断字符串、数字等;
注:Object.prototype.toString.call() 适用于所有类型的判断检测。
1 | Object.prototype.toString.call(1); // [object Number] |
封装一下typeof方法
1 | function myTypeof(val) { |
如何实现深拷贝
判断数组有哪几种方法
instanceof
instanceof是判断变量是否为某个对象的实例,返回值为true或false。Object.prototype.toString.call()
每一个继承 Object 的对象都有 toString 方法,如果 toString 方法没有重写的话,会返回[Object type],其中 type 为对象的类型。但当除了 Object 类型的对象外,其他类型直接使用 toString 方法时,会直接返回都是内容的字符串,所以我们需要使用 call 或者 apply 方法来改变 toString 方法的执行上下文。该方法对于所有基本的数据类型都能进行判断。Array.isArray()
此方法用来判断对象是否为数组。
操作数组方法有哪些,分别有什么用
1 | let arr = [11, 22, 33] |
1 | // 1. pop() 方法从数组中删除最后一个元素,并返回该元素的值。此方法更改数组的长度。 |
1 | // 2. shift() 方法从数组中删除第一个元素,并返回该元素的值。此方法更改数组的长度。 |
1 | // 3. push() 方法将一个或多个元素添加到数组的末尾,并返回该数组的新长度。 |
1 | // 4. unshift() 方法将一个或多个元素添加到数组的开头,并返回该数组的新长度。 |
1 | // 5. concat() 方法用于合并两个或多个数组。此方法不会更改现有数组,而是返回一个新数组。 |
1 | // 6. slice() 方法返回一个新的数组对象,这一对象是一个由 begin 和 end 决定的原数组的浅拷贝(包括 begin,不包括end),原始数组不会被改变。 |
1 | // 7. filter() 方法创建一个新数组, 其包含通过所提供函数实现的测试的所有元素,不改变原数组。 |
1 | // 8. map() 方法创建一个新数组,其结果是该数组中的每个元素是调用一次提供的函数后的返回值。 |
1 | // 9. splice() 方法通过删除或替换现有元素或者原地添加新的元素来修改数组,并以数组形式返回被修改的内容。此方法会改变原数组。 |
数组降维
null与undefined的区别
null:null 是一个字面量,表示空,没有对象。
用法:
- 作为函数的参数,表示该函数的参数不是对象。
- 作为对象原型链的终点。
undefined:undefined 表示 “缺少值“,就是此处应该有一个值,但是还没有定义。
用法:
- 变量被声明了,但没有赋值时,就等于
undefined; - 调用函数时,应该提供的参数却没有提供,该参数等于
undefined; - 对象没有赋值的属性,该属性的值为
undefined; - 函数没有返回值时,默认返回
undefined;
惯例:
- 如果一个变量没有赋值,那它就是
undefined; - 如果一个对象
Object,现在还不想赋值,则可以给它一个null,即:let obj = null,表示空对象; - 如果有一个非对象,现在还不想赋值,则给它一个
undefined;
注意:
1 | null == undefined // true |
Promise、Promise.all、Promise.race分别怎么用
async/await语法了解吗,目的是什么
什么是立即执行函数,使用立即执行函数的目的是什么
立即执行函数就是说这个函数是立即执行函数体的,不需要额外的去主动调用,要成为立即执行函数,需要满足两个条件:
- 声明一个匿名函数;
- 立马调用这个匿名函数;
立即执行函数的目的是 创建独立的作用域,让外部无法访问作用域内部的变量,从而避免 变量污染。
下面这段代码就是一个立即执行函数:
1 | (function(){ |
除了上面这种写法,还有如下写法:
1 | // (匿名函数()) |
如何实现数组去重
如何用正则实现string.trim()
trim() 方法会从一个字符串的两端删除空白字符。
1 | function trim(string) { |
合并对象的几种方法
- 利用 Object.assign 合并多个对象;
1 | let obj1 = { |
- 利用扩展运算符
1 | let obj1 = { |
- 利用浅拷贝实现
1 | let merger = (...opts) => { |
- 利用深拷贝实现
1 | let merger = (...opts) => { |
- 利用 lodash 中的 merge() 方法
1 | const _ = require('lodash'); |
了解ES6 class的用法吗
基本用法:
在没有 ES6 class 之前的常规写法:
1 | function Person(name, age) { |
在 ES6 中新增加了类的概念,可以使用 class 关键字声明一个类,之后以这个类来实例化对象。
类抽象了对象的公共部分,它泛指某一大类。
对象特指某一个,通过类实例化一个具体的对象。
1 | class Star { |
注意:
- 类必须使用 new 实例化对象
- 通过 class 关键字创建类,类名首字母一般大写
- 类里面有个 constructor 函数,可以接收传递过来的参数,同时返回实例对象
- 类里面所有函数都不需要写 function
- 多个函数方法之间不需要用逗号隔开
类的继承:
JavaScript 中的类可以继承某个类,其中被继承的类称为父类,而继承父类的被称为子类。
子类可以有自己的函数和构造器,当子类中存在父类相同的方法时,则该方法不会从父类继承,而使用子类的方法。
1 | class Father { |
super关键字:
super 关键字用于访问和调用对象父类上的函数。可以调用父类的构造函数,也可以调用父类的普通函数。
1 | class Father { |
注意:
- 在 ES6 中类没有变量提升,所以必须先定义类,才能通过类实例化对象
- 类里面的共有的属性和方法一定要加 this
- this 的指向问题;constructor 里面的 this 指向的是创建的实例对象;方法里面的 this 指向这个方法的调用者
axios与ajax的区别
模块化
如何实现一个call函数
1 | Function.prototype.myCall = function(context) { |
如何实现一个apply函数
1 | Function.prototype.myApply = function(context) { |
如何实现一个bind函数
1 | Function.prototype.myBind = function(context) { |
手写一个AJAX
1 | let xhr = new XMLHttpRequest() |
手写一个函数防抖
当我们触发事件时,但是一定在事件触发的第 n 秒后才执行,如果你在一个事件触发的 n 秒内又触发了这个事件,那么就以新触发事件的时间为准,n 秒后才执行。
就是等你触发完事件 n 秒内不再触发事件才会执行。
也可以这样理解,相当于王者荣耀游戏里的回城功能一样,如果你反复的触发点击,只会以最后一次为准。
1 | function debounce(fn, wait) { |
手写一个函数节流
从上一次命令结束开始的一定时间范围 n 秒内,如果多次连续下达命令,则只执行当前时间段 n 秒内第一次命令。
如果你持续触发事件,每隔一段时间,只执行一次事件。
1 | function throttle(fn, gapTime) { |
手写EventHub
1 | class EventHub { |
手写简易版的jQuery
手写一个Promise
什么是事件委托
事件委托,其实就是把一个元素响应事件(click、keydown…)的函数委托到另一个元素上。
一般来说,我们会把一个或者一组元素的事件委托到它的父层或者更外层元素上,真正绑定事件的是外层元素,当事件响应到需要绑定的元素上时,会通过事件冒泡机制从而触发它的外层元素的绑定事件上,然后在外层元素上去执行函数。
使用事件委托的好处:
- 可以减少内存的消耗;
- 动态绑定事件;
WebSocket是什么,了解吗
我提问你来答
Topic One:
如何让下面代码打印出来!
1 | if (a == 1 && a == 2 && a == 3) { |
1 | let a = { |
Topic Two:
如何让下面代码打印出来!
1 | if (a === 1 && a === 2 && a === 3) { |
1 | let _default = 0 |
Topic Three:
下面几段代码将打印出什么呢?
1 | console.log(({} + {}).length); |
分别打印出:30 0 0。
1 | console.log({}.toString()); // [object Object] |
Topic Four:
这行代码的执行结果是什么?
1 | console.log(['1', '2', '3'].map(parseInt)) |
首先我们先来了解下 map 的使用。
1 | ['1', '2', '3'].map(function(item, index) { |
再来看看 parseInt 的使用。
1 | parseInt(1) // 1 |
我们来看看 parseInt('1', 2) 的执行步骤:
- 将
'1'转换成数字; - 然后把它当作二进制数;
- 最后返回十进制数。
注意:parseInt 是向下取整。并且第二个参数表示字符串的基数,是 2~36 之间的整数。
现在我们再来看看这段代码:
1 | ['1', '2', '3'].map(parseInt) |
可以这样等价于:
1 | ['1', '2', '3'].map(function parseInt(item, index) { |
所以最后结果是:[1, NaN, NaN]。
其他
Vue
对SPA单页面的理解,它的优缺点分别是什么
SPA 在 Web 页面初始化时加载相应的 HTML、CSS、JavaScript。一旦页面加载完成,SPA 不会因为用户的操作而进行页面的重新加载或跳转。取而代之的是利用路由机制实现 HTML 内容的变换,UI与用户的交互,避免页面的重新加载。
优点:
- 用户体验好且快,内容的改变不需要重新加载整个页面,避免了不必要的跳转和重复的渲染;
- SPA 单页面对服务器的压力小;
- 前后端职责分离,架构清晰,前端进行交互逻辑,后端负责数据处理。
缺点:
- 初次加载比较耗时:为实现单页 Web 应用功能及显示效果,需要在加载页面的时候将 CSS、JavaScript 这些都统一加载,部分页面按需加载;
- 前进后退路由管理:由于单页应用在一个页面中显示所有的内容,所以不能使用浏览器的前进后退功能,所有的页面切换需要自己建立堆栈来管理;
- SEO 难度较大:由于所有的内容都在一个页面中动态替换显示,所以在 SEO 上比较弱。
生命周期
Vue的生命周期有哪些
- 创建:
beforeCreate,created; - 载入:
beforeMount,mounted; - 更新:
beforeUpdate,updated; - 销毁:
beforeDestroy,destroyed。
生命周期示意图:

第一次页面加载会触发哪几个钩子
beforeCreate、created、beforeMount、mounted。
每一个周期具体适合哪些场景
beforeCreate:在 new 一个 Vue 实例后,只有一些默认的生命周期钩子和默认事件,其他的东西都还没创建。不能获取 DOM 节点。data 和 methods 中的数据都还没有初始化,不能在这个阶段使用 data 中的数据和 methods 中的方法。created:实例已经创建,仍不能获取 DOM 节点,data 和 methods 都已经被初始化好了,如果要调用 methods 中的方法,或者操作 data 中的数据,最早可以在这个阶段里操作。beforeMount:在内存中已经编译好模板了,但是还没有挂载到页面中,此时,页面还是旧的。mounted:Vue 实例已经初始化完成了,此时组件脱离了创建阶段,进入到运行阶段。如果我们想要通过插件操作页面上的 DOM 节点,最早可以在这个阶段中进行。beforeUpdate:当执行这个钩子时,页面中的显示的数据还是旧的,data 中的数据是更新后的,页面还没有和最新的数据保持同步。updated:页面显示的数据和 data 中的数据已经保持同步了,都是最新的。beforeDestroy:Vue 实例从运行阶段进入到了销毁阶段,这个时候所有的 data、methods、指令、过滤器等等都是处于可用状态,还没有真正被销毁。destroyed:组件已经被销毁,无法操作里面的任何东西了。
Vue获取数据一般在哪个周期函数
在 created、beforeMount、mounted 中都可以。
不要在 updated 里更新数据。
父子组件在生命周期中调用的顺序是怎样的
- 加载渲染过程:
父beforeCreate -> 父created -> 父beforeMount -> 子beforeCreate -> 子created -> 子beforeMount -> 子mounted -> 父mounted; - 父组件更新过程:
- 影响到子组件:
父beforeUpdate -> ⼦beforeUpdate -> ⼦updated -> ⽗updated; - 不影响子组件:
父beforeUpdate -> 父updated;
- 影响到子组件:
- 子组件更新过程:
- 影响到父组件:
父beforeUpdate -> 子beforeUpdate -> 子updated -> 父updated; - 不影响父组件:
⼦beforeUpdate -> ⼦updated;
- 影响到父组件:
- 销毁过程:
父beforeDestroy -> 子beforeDestroy -> 子destroyed -> 父destroyed。
与keep-alive有关的生命周期有哪些并简述
有两个生命周期函数:
activated:被keep-alive缓存的组件激活时调用;deactivated:被keep-alive缓存的组件停用时调用。
当页面第一次进入的时候,触发的顺序是 created -> mounted -> activated,然后退出的时候会触发 deactivated。但是当再次进入的时候(前进 or 后退),只会触发 deactivated。
watch和created哪个先执行,为什么
在一般情况下,created 会比 watch 先执行,watch 会在监听的数据发生变化后才执行。
但是呢,如果我们给 watch 设置了 immediate: true ,那么在初始化时就会调用函数,然后再执行 created。
怎样让CSS只在当前组件中生效
在组件中的 style 标签上加上 scoped。
1 | <style scoped></style> |
template下为什么只能有一个div呢
如何给vue自定义组件添加点击事件
官方文档 给出,.native - 监听组件根元素的原生事件。
1 | <my-button @click.native="eventName()" /> |
如何获取DOM
Vue常用的指令有哪些
v-html:会将html代码解析出来并进行渲染;v-text:输出文本;v-if:条件判断指令;v-show:是否隐藏元素;v-for:循环指令;v-bind:属性绑定指令(数据的单向绑定);v-model:实现数据的双向绑定;v-on:绑定事件指令;v-once:表示元素和组件只会渲染一次;v-pre、v-cloak;
详情请参考 Vue - 指令
v-html会导致什么问题
可能会导致 XSS 攻击,因此在网站上只能在可信的内容上使⽤ v-html,并且永远不能把它⽤于⽤户提交的内容上面。
computed和watch的区别
computed:computed 是计算属性,它会根据你所依赖的数据动态显示新的计算结果。计算结果会被缓存,computed 的值在 getter 执行后是会被缓存的,只有在它依赖的属性值改变之后,下一次获取 computed 的值时才会重新调用对应的 getter 来计算。
应用场景:购物车商品结算,当我们需要进行数值计算,并且依赖于其它数据时,应该使用 computed,可以利用 computed 的缓存特性,避免每次获取值时,都要重新计算。
watch:watch 是去监听一个值的变化,然后执行相对应的函数。它可以接受 2 个参数(newValue, oldValue),即变化的最新值和上一次变化的旧值。它是没有缓存的。
应用场景:搜索数据,如果你需要在某个数据变化时做一些事情,使用 watch 来观察这个数据变化。
v-show与v-if的区别
v-show的本质是改变display的值,不管初始条件是什么,都会渲染。v-if是动态向DOM树内添加或者删除DOM元素。
v-show 就是控制 CSS 的 display,而 v-if 是不停的销毁和创建,因此如果需要频繁切换使用 v-show 性能会更好一点。
v-if和v-for的优先级是什么
根据 官方文档 所描述的:不推荐同时使用 v-if 和 v-for。如果 v-if 与 v-for 一起使用时,v-for 具有比 v-if 更高的优先级。
这也就意味着 v-if 将分别重复运行于每个 v-for 循环中。因此是不推荐将这个两个指令同时使用。
什么是MVVM
MVVM 是 Model-View-ViewModel 的缩写,它是一种设计思想。
Model层代表数据模式,也可以在Model中定义数据修改和操作的业务逻辑;View代表UI组件,它负责将数据模型转化为UI展现出来;ViewModel是一个同步View和Model的对象。
Vue组件之间如何通信
Vue中key值的作用是什么
使用 key 来给每个节点做一个唯一标识,Diff 算法就可以正确的识别此节点。
key 的作用主要是为了高效的更新虚拟 DOM,可以减少渲染次数,提升渲染性能。
v-model的原理
v-model 就是一个语法糖,它背后本质是包含了两个操作:
v-bind绑定一个value属性;v-on给当前元素绑定input事件。
1 | <input type="text" v-model="message"> |
Class与Style如何动态绑定
Class - 对象语法:
绑定 class 对象语法:对象的键是类名,值是布尔值。
1 | <div v-bind:class="{ active: isActive, size: isSize }">对象绑定Class</div> |
1 | data: { |
或者下面这种写法:
1 | <div :class="classObj">对象绑定Class</div> |
1 | data: { |
当需要动态添加 class 时,需要使用 Vue.set() 方法。
Class - 数组语法:
绑定 class 数组语法:数组中的成员直接对应类名。
1 | <div v-bind:class="[isActive,isSize]">数组绑定class</div> |
1 | data: { |
或者下面这种写法:
1 | <div :class="classArr">数组绑定Class</div> |
1 | data: { |
Style - 对象语法:
1 | <div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }">对象绑定Style</div> |
1 | data: { |
或者下面这种写法:
1 | <div :style="styleObj">对象绑定Style</div> |
1 | data: { |
当需要动态添加 style 时,需要使用 Vue.set() 方法。
Style - 数组语法:
1 | <div v-bind:style="[styleColor, styleSize]">数组绑定Style</div> |
1 | data: { |
或者下面这种写法:
1 | <div :style="styleArr">数组绑定Style</div> |
1 | data: { |
Vue的修饰符有哪些
表单修饰符:.lazy:让数据在失去焦点或者回车时才会更新同步;.number:自动将用户的输入值转为数值类型;.trim:自动过滤用户输入的首尾空白字符;
事件修饰符:.stop:阻止冒泡;.prevent:阻止默认行为;.self:只会触发自己范围内的事件,不包含子元素;.once:事件将只会触发一次;.capture:与事件冒泡的方向相反,事件捕获由外到内;.passive:Vue 还对应 addEventListener 中的 passive 选项提供了 .passive 修饰符,能够提升移动端的性能。
不要把 .passive 和 .prevent 一起使用,因为 .prevent 将会被忽略,同时浏览器可能会向你展示一个警告。请记住,.passive 会告诉浏览器你不想阻止事件的默认行为。
按键修饰符:.enter:回车键;.tab:制表键;.delete:含删除和退格键;.esc:返回键;.space: 空格键;.up:向上键;.down:向下键;.left:向左键;.right:向右键;
系统修饰键:
可以用这几个修饰符来实现仅在按下相应按键时才触发鼠标或键盘事件的监听器:.ctrl、.alt、.shift、.meta。
鼠标按钮修饰符:.left:左键点击;.right:右键点击;.middle:中键点击;
.exact修饰符:.exact:修饰符允许你控制由精确的系统修饰符组合触发的事件。
1 | <!-- 即使 Alt 或 Shift 被一同按下时也会触发 --> |
Vue组件中data为什么是函数
什么是动态组件
如果有多个组件需要通过同一个挂载点来进行组件的切换,此时就可以用到动态组件,使用 component 标签,并使用 :is,它的值是哪个组件的名称,那么就会显示哪个组件。
1 | <component :is="otherComponent"></component> |
什么是异步组件
在大型应用中,我们可能需要将应用分割成小一些的代码块,并且只在需要的时候才从服务器加载一个模块。为了简化,Vue 允许你以一个工厂函数的方式定义你的组件,这个工厂函数会异步解析你的组件定义。Vue 只有在这个组件需要被渲染的时候才会触发该工厂函数,且会把结果缓存起来供未来重渲染。
1 | components: { |
keep-alive的作用是什么
keep-alive 是 Vue 内置的一个组件,可以使被包含的组件保留状态,或避免重新渲染。
Vue是如何实现数据的双向绑定的
Vue 双向数据绑定是通过 数据劫持 结合 发布订阅模式 的方式来实现的,也就是说数据和视图同步,如果数据发生变化,那么视图也跟着变化,视图变化,数据也随之发生改变;其核心是 Object.defineProperty() 方法。
过滤器是什么,怎么使用呢
Vue.js 允许你自定义过滤器,可被用于一些常见的文本格式化。过滤器可以用在两个地方:双花括号插值和 v-bind 表达式。过滤器应该被添加在 JavaScript 表达式的尾部,由 “管道” 符号指示:
1 | <!-- 在双花括号中 --> |
有两种注册方式:全局注册、局部注册。
1 | // 全局注册 |
注意:当全局过滤器和局部过滤器重名时,会采用局部过滤器。
PS:从 Vue 3.0 开始,过滤器已删除,不再支持。在 3.x 中,可以用方法调用或计算属性替换它们。
Vue中的$nextTick有什么作用
Vue.nextTick(callback):在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。vm.$nextTick(callback):将回调延迟到下次 DOM 更新循环之后执行。在修改数据之后立即使用它,然后等待 DOM 更新。
看如下代码:
1 | <button @click="add">add</button> |
1 | let app = new Vue({ |
当我们点击按钮后,会发现控制台打印出 3,这不是我们想要的,我们认为此时应该打印出 4,这时候需要用到 $nextTick 来解决此问题。
1 | add() { |
对mixin的理解,有什么应用场景
Vue.observable()有什么用,怎么用
它可以让一个对象可响应。Vue 内部会用它来处理 data 函数返回的对象。
返回的对象可以直接用于渲染函数和计算属性内,并且会在发生变更时触发相应的更新。也可以作为最小化的跨组件状态存储器。
在 Vue 2.x 中,被传入的对象会直接被 Vue.observable 变更,它和被返回的对象是同一个对象。而在 Vue 3.x 中,则会返回一个可响应的代理,而对源对象直接进行变更仍然是不可响应的。
在非父子组件通信时,可以使用 EventBus 或者 Vuex,但是如果实现的功能不是很复杂,就可以使用 observable。
创建 observable.js 文件:
1 | import Vue from 'vue' |
然后随便在一个 vue 文件中使用:
1 | <template> |
1 | <script> |
自定义指令怎么写
自定义指令分全局注册和局部注册。
全局注册:通过 Vue.directive 方法进行注册。
局部注册:通过在组件 options 选项中设置 directive 属性。
1 | // 全局注册 |
1 | // 局部注册 |
自定义指令有如下几个钩子函数:
- bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
- inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。
- update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新。
- componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用。
- unbind:只调用一次,指令与元素解绑时调用。
指令钩子函数会被传入以下参数:
- el:指令所绑定的元素,可以用来直接操作 DOM。
- binding:一个对象,包含以下 property:
- name:指令名,不包括
v-前缀。 - value:指令的绑定值,例如:
v-my-directive="1 + 1"中,绑定值为 2。 - oldValue:指令绑定的前一个值,仅在
update和componentUpdated钩子中可用。无论值是否改变都可用。 - expression:字符串形式的指令表达式。例如
v-my-directive="1 + 1"中,表达式为"1 + 1"。 - arg:传给指令的参数,可选。例如
v-my-directive:foo中,参数为 “foo”。 - modifiers:一个包含修饰符的对象。例如:
v-my-directive.foo.bar中,修饰符对象为{ foo: true, bar: true }。
- name:指令名,不包括
- vnode:Vue 编译生成的虚拟节点。
- oldVnode:上一个虚拟节点,仅在
update和componentUpdated钩子中可用。
注意:除了 el 之外,其它参数都应该是只读的,切勿进行修改。如果需要在钩子之间共享数据,建议通过元素的 dataset 来进行。
什么是虚拟DOM
vue2.0兼容IE哪个版本
不支持 IE8 及以下,因为 Vue 的双向绑定原理是 Object.defineProperty,IE8 及以下不支持此 API。部分兼容 IE9,完全兼容 IE10 以上。
Vue有哪些推荐的风格指南
- 组件名为多个单词,这样可以避免跟现有的以及未来的
HTML元素相冲突,例如:todo-item; - 组件的
data必须是一个函数; Prop定义应该尽量详细;- 使用
v-for时,必须使用key; - 避免
v-if和v-for用在同一个元素上; - 为组件样式设置作用域(scoped);
- …
更多详情请参考 Vue.js 风格指南
如何解决动态设置img的src不生效
1 | <template> |
Vue-Router
vue-router路由模式有几种
有两种模式,分别为 hash 模式和 history 模式。
hash 模式:
地址栏 URL 中的 # 符号。比如此 URL:https://www.lqzww.top/posts/4a5e2e1d/#vue-router,hash 的值为#vue-router。
url路径会出现#字符;hash值不包括在Http请求中,它是由前端路由处理,所以改变hash值时不会刷新页面,也不会向服务器发送请求;hash值的改变会触发hashchange事件;
history 模式:
利用了 HTML5 History Interface 中新增的 pushState() 和 replaceState() 方法。这两个方法应用于浏览器的历史记录栈,在当前已有的 back、forward、go 的基础之上,它们提供了对历史记录进行修改的功能。只是当它们执行修改时,虽然改变了当前的 URL,但浏览器不会立即向后端发送请求。
- 整个地址重新加载,可以保存历史记录,方便前进后退;
- 依赖 H5 API 和后台配置,没有后台配置的话,页面刷新时会出现
404;
hash模式和history模式有什么区别
hash模式url带#号,而history模式不带#号;- 刷新⻚⾯时,
hash模式可以加载到hash值对应的⻚⾯,⽽history模式没有处理的话,会返回404; hash⽀持低版本浏览器和IE,而history是HTML5新推出的API。
vue-router有哪几种导航钩子
vue-router 提供的导航守卫主要用来通过跳转或取消的方式守卫导航。有多种机会植入路由导航过程中:全局的、单个路由独享的、组件级的。
参数或查询的改变并不会触发 进入 / 离开 的导航守卫。你可以通过观察 $route 对象来应对这些变化,或使用 beforeRouteUpdate 的组件内守卫。
- 全局守卫:
router.beforeEach; - 全局解析守卫:
router.beforeResolve; - 全局后置钩子:
router.afterEach; - 路由独享的守卫:
beforeEnter; - 组件内的守卫:
beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave;
vue-router导航解析的流程是什么
- 导航被触发。
- 在失活的组件里调用
beforeRouteLeave守卫。 - 调用全局的
beforeEach守卫。 - 在重用的组件里调用
beforeRouteUpdate守卫 (2.2+)。 - 在路由配置里调用
beforeEnter。 - 解析异步路由组件。
- 在被激活的组件里调用
beforeRouteEnter。 - 调用全局的
beforeResolve守卫 (2.5+)。 - 导航被确认。
- 调用全局的
afterEach钩子。 - 触发
DOM更新。 - 调用
beforeRouteEnter守卫中传给next的回调函数,创建好的组件实例会作为回调函数的参数传入。
route和router的区别
$route为当前 router 跳转对象,里面可以获取当前路由的fullPath、hash、metched、meta、name、path、params、query路由信息参数。$router是VueRouter的实例,是全局的路由对象,里面包括了路由的跳转方法,钩子函数等等。
在vue组件中如何获取到当前的路由信息
通过使用 this.$route 来获取。
路由跳转方式有哪些
- router-link
- this.$router.push()
- this.$router.replace()
- this.$router.go()
- this.$router.forward()
- this.$router.back()
vue-router实现路由懒加载
active-class是哪个组件的属性
active-class 它是属性 vue-router 的样式方法,当 router-link 标签被点击时,就会使用该样式。
有如下两种使用方法:
直接在
router-link标签上使用:1
<router-link to="/about" active-class="active">about</router-link>
在
router/index.js文件中配置:1
2
3
4const router = new VueRouter({
routes,
linkActiveClass: 'active'
})
注意:在首页的 active 会被一直应用着。
解决办法:
添加
exact属性:1
<router-link to="/" active-class="active" exact>home</router-link>
在
router/index.js文件中配置:1
2
3
4const router = new VueRouter({
routes,
linkExactActiveClass: 'active'
})
vue-router中params与query的区别
query 传参与接收参数的方式:
1 | this.$router.push({ |
params 传参与接收参数的方式:
1 | this.$router.push({ |
区别如下:
- 用法:query 用
path来引入,而 params 用name来引入; - url:query 传递的参数要在浏览器地址栏上显示,而 params 不会显示;
- 刷新:query 刷新不会丢失 query 里面的数据,而 params 刷新会丢失 params 里面的数据。
vue-router怎么配置404页面
1 | const routes = [ |
注意:需要将 404 页面放到路由的最后面。
vue-router怎样响应路由参数的变化呢
当使用路由参数时,例如从 /user/foo 导航到 /user/bar,原来的组件实例会被复用。因为两个路由都渲染同一个组件,比起销毁再创建,复用则显得更加高效。不过,这也意味着组件的生命周期钩子不会再被调用。
利用 watch 监听
1
2
3
4
5watch: {
$route(to, from){
// 对路由变化作出响应...
}
}利用 beforeRouteUpdate 导航守卫
1
2
3
4
5
6
7
8
9const User = {
template: `...`,
beforeRouteUpdate(to, from, next) {
// 在当前路由改变,但是该组件被复用时调用
// 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
// 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
// 可以访问组件实例 `this`
},
}router-view 上加个 key
1
<router-view :key="$route.fullPath"></router-view>
$route.fullPath 是完成后解析的 URL,包含其查询参数信息和 hash 完整路径
Vuex
Vuex是什么,怎么使用,哪种功能场景使用它
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。它实现组件全局状态(数据)管理的一种机制,可以方便的实现组件之间数据的共享。
使用 Vuex 统一管理状态有如下好处:
- 能够在 vuex 中集中管理共享的数据,易于开发和后期维护;
- 能够高效地实现组件之间的数据共享,提高开发效率;
- 存储在 vuex 中的数据都是响应式的,能够实时保持数据与页面的同步;
在 main.js 引入 store,注入。新建了一个 store 目录,然后 ...export。
场景:单页应用中,组件之间的共享状态和方法。
Vuex有哪几种属性
State:用于数据的存储,提供唯一的公共数据源,所有共享的数据都要统一放到Store的State中进行存储;Getter:用于对Store中的数据进行加工处理形成新的数据,类似 Vue 中的计算属性,Store中数据发生变化,Getter的数据也会跟着变化;Mutation:用于变更Store中的数据,且不能用于处理异步操作;Action:用于处理异步任务,如果通过异步操作变更数据,必须通过Action,而不能使用Mutation,但是在Action中还是要通过触发Mutation的方式间接变更数据;Module:类似于命名空间,用于项目中将各个模块的状态分开进行定义和操作;
Vuex中actions和mutations有什么区别
mutations:它只能进行同步操作,可以直接修改state,通过commit进行提交。actions:它进行异步操作,是无法直接修改state,只能通过触发mutation的方式间接变更数据,通过dispatch进行触发。
它们具体的使用请查看 Vue2从入门到放弃。
页面刷新后state数据丢失了怎么办
- 将
state数据保存在localstorage、sessionstorage或者cookie中; - 使用vuex-persistedstate。
Vue-Loader
vue-loader是什么及用途
vue-loader 是解析 .vue 文件的一个加载器,它可以将 template / js / style 转换成 JS 模块。
⽤途:JS 可以写 ES6、style 样式可以 scss / less、template 可以加 jade 等等。
Vue3
Options Api与Composition Api的区别
Options Api:选项 API,可以用包含多个选项的对象来描述组件的逻辑,通过定义 data、methods,computed,watch 等属性与方法,共同处理页面逻辑。当组件变得复杂,会导致对应属性的列表也会增长,这可能会导致组件难以阅读和理解。
Composition Api:组合式 API,组件根据逻辑功能来组织的,一个功能所定义的所有 API 会放在一起(更加的高内聚,低耦合)。
- 在逻辑组织和逻辑复用方面,Composition API 是优于 Options API 的;
- Composition API 几乎都是函数,会有更好的类型推断;
- Composition API 对 tree-shaking 友好,代码也更容易压缩;
- Composition API 中见不到 this 的使用,减少了 this 指向不明的情况;
script setup是什么
它是 vue3 的语法糖,简化了组合式 API,它有如下特点:
- 属性和方法都无需返回,可以直接使用;
- 引入组件的时候,会自动注册,无需使用
components来手动注册; - 使用
defineProps接收父组件传递的值,使用defineEmits获取自定义事件; useAttrs获取属性,useSlots获取插槽;- 默认不会对外暴露任何属性,如果需要可使用
defineExpose;
注意:部分答案来源于网络,如发现有错误,请联系我修正,谢谢!
本文将不定期持续更新,欢迎您收藏本站!😘
- 1. HTTP
- 2. HTML
- 3. CSS
- 3.1. css hack是什么
- 3.2. 两种盒模型
- 3.3. 为什么要初始化CSS样式
- 3.4. 块级元素与行内元素分别有哪些以及各有什么特点
- 3.5. position有哪些常用的值
- 3.6. CSS中伪类与伪元素的区别
- 3.7. 如何水平居中
- 3.8. 如何垂直居中
- 3.9. flex怎么用,常用属性有哪些
- 3.10. grid布局怎么用
- 3.11. display:none; 、visibility:hidden; 、opacity:0; 有什么区别
- 3.12. BFC是什么,举例回答
- 3.13. CSS选择器的优先级
- 3.14. CSS哪些属性可以继承
- 3.15. 如何清除浮动
- 3.16. em与rem
- 3.17. px、em、rem区别
- 3.18. CSS3有哪些新特性
- 3.19. 去除inline-block元素间间隙的方法
- 3.20. 如何适配各种移动设备
- 3.21. 如何添加代码使得图片宽度为300px
- 3.22. 用纯CSS画一个三角形
- 3.23. 用纯CSS画一个六边形
- 3.24. width:auto;和width:100%;的区别是什么
- 3.25. 什么是优雅降级和渐进增强
- 3.26. line-height是如何继承的
- 3.27. 怎么画一条0.5px的线
- 3.28. 文本省略有哪些方案
- 3.29. 300ms延迟解决方案
- 3.30. 什么是重绘和重排
- 4. JavaScript
- 4.1. JS的基础数据类型有哪些
- 4.2. JS中null是对象吗
- 4.3. export与export default的区别
- 4.4. import与require的区别
- 4.5. ES6语法有哪些,分别怎么用
- 4.6. new的执行过程
- 4.7. 异常捕获
- 4.8. call、apply、bind区别
- 4.9. 什么是JSONP
- 4.10. 全局函数eval()有什么作用
- 4.11. 为什么0.1+0.2!==0.3
- 4.12. ==、=== 与 Object.is()
- 4.13. 什么是原型
- 4.14. 什么是闭包
- 4.15. 什么是CORS,什么是跨域
- 4.16. typeof与instanceof区别
- 4.17. 封装一下typeof方法
- 4.18. 如何实现深拷贝
- 4.19. 判断数组有哪几种方法
- 4.20. 操作数组方法有哪些,分别有什么用
- 4.21. 数组降维
- 4.22. null与undefined的区别
- 4.23. Promise、Promise.all、Promise.race分别怎么用
- 4.24. async/await语法了解吗,目的是什么
- 4.25. 什么是立即执行函数,使用立即执行函数的目的是什么
- 4.26. 如何实现数组去重
- 4.27. 如何用正则实现string.trim()
- 4.28. 合并对象的几种方法
- 4.29. 了解ES6 class的用法吗
- 4.30. axios与ajax的区别
- 4.31. 模块化
- 4.32. 如何实现一个call函数
- 4.33. 如何实现一个apply函数
- 4.34. 如何实现一个bind函数
- 4.35. 手写一个AJAX
- 4.36. 手写一个函数防抖
- 4.37. 手写一个函数节流
- 4.38. 手写EventHub
- 4.39. 手写简易版的jQuery
- 4.40. 手写一个Promise
- 4.41. 什么是事件委托
- 4.42. WebSocket是什么,了解吗
- 4.43. 我提问你来答
- 4.44. 其他
- 5. Vue
- 5.1. 对SPA单页面的理解,它的优缺点分别是什么
- 5.2. 生命周期
- 5.3. watch和created哪个先执行,为什么
- 5.4. 怎样让CSS只在当前组件中生效
- 5.5. template下为什么只能有一个div呢
- 5.6. 如何给vue自定义组件添加点击事件
- 5.7. 如何获取DOM
- 5.8. Vue常用的指令有哪些
- 5.9. v-html会导致什么问题
- 5.10. computed和watch的区别
- 5.11. v-show与v-if的区别
- 5.12. v-if和v-for的优先级是什么
- 5.13. 什么是MVVM
- 5.14. Vue组件之间如何通信
- 5.15. Vue中key值的作用是什么
- 5.16. v-model的原理
- 5.17. Class与Style如何动态绑定
- 5.18. Vue的修饰符有哪些
- 5.19. Vue组件中data为什么是函数
- 5.20. 什么是动态组件
- 5.21. 什么是异步组件
- 5.22. keep-alive的作用是什么
- 5.23. Vue是如何实现数据的双向绑定的
- 5.24. 过滤器是什么,怎么使用呢
- 5.25. Vue中的$nextTick有什么作用
- 5.26. 对mixin的理解,有什么应用场景
- 5.27. Vue.observable()有什么用,怎么用
- 5.28. 自定义指令怎么写
- 5.29. 什么是虚拟DOM
- 5.30. vue2.0兼容IE哪个版本
- 5.31. Vue有哪些推荐的风格指南
- 5.32. 如何解决动态设置img的src不生效
- 6. Vue-Router
- 7. Vuex
- 8. Vue-Loader
- 9. Vue3











