前端面试

Evan MVP+

Vue、小程序语法对比

Vue2、Vue3父子通信

工作相关

项目开发流程

布局时,先画盒子,确定盒子大小,边距后再填内容

写逻辑时,以数据为中心,围绕数据进行操作

json-server模拟数据

其他

微信登录&支付

个人开发者不能调用微信登录&支付

购物车实现

总价和商品总数量利用计算属性配合 reduce 实现,同时在内层需要加一层判断,只有选中的商品才会参与计算

单个商品数量变化时,需要发请求修改后端数据、更新页面数据

单选时,每次点击都要判断是否全部选中、同时选中/取消选中

全选时,需要一并修改所有单选按钮的状态

函数柯里化

函数套函数,简称套娃函数

好处:相比单个函数更灵活,可控,可复用

团队协作工具

我们公司用 PinCode、Tower、禅道管理项目进度和流程

修改组件默认样式

如果不生效,可以:

  • 加 !important
  • 加 ::v-deep

uni-number-box数字输入框组件,change事件自定义传参

https://uniapp.dcloud.net.cn/component/uniui/uni-number-box.html

方式一:

uni-number-box【数字输入框组件】,change事件 自定义传参

方式二:使用 $event 保留原事件对象

1
<uni-number-box :min="1" :max="item.goods.stock_total" :value="item.goods_num" @change="onChangeCount($event, item)" />

HTML&CSS

选择器优先级

CSS 选择器的优先级顺序为:

1
!important > 行内样式 > id选择器 > class类选择器 > 标签选择器 > 通配符选择器 > 继承

如果一个CSS规则有多个选择器,就要计算整体的权重

隐藏元素的几种方式

要让页面中的元素隐藏,有好几种方式

display: none;

隐藏元素,不占空间,不可交互

visibility: hidden;

让元素在页面上不可见,保留空间,不可交互

opacity: 0;

让元素看起来不可见,保留空间,可交互

此外,还有一些投机取巧的方式:

  • z-index: -9999 将元素置于最底层,被其他元素遮挡
  • transform: scale(0,0) 将元素缩放到看不见
  • left: -9999px:将元素移到页面可视范围之外

定位

定位用来改变盒子在网页中的位置,共有 5 种定位方式

1.static 静态定位(默认)

  • 元素按照在正常文档流中的位置显示,块元素从上往下排列,行内元素从左往右排列
  • 对静态定位的元素设置 top、left、right、bottom、z-index 无效

2.relative 相对定位

  • 相对于元素本来的位置进行定位

3.absolute 绝对定位

  • 相对于最近的非 static 定位的祖先元素进行定位

4.fixed 固定定位

  • 相对于浏览器窗口进行定位
  • 固定在窗口的某一位置,当屏幕向下滚动时,不会跟随移动

5.sticky 粘性定位

  • 这种定位方式比较特别,一开始是相对定位,当屏幕向下滚动到一定区域后,变成固定定位
1
2
3
4
.nav {
position: fixed;
top: 0
}

定位后的元素层级提高,在普通元素上方显示

这几种定位方式中,只有绝对定位和固定定位会脱标。脱标后的元素不占空间,可以影响页面布局,并且具备行内块的特点

我们在布局时,要遵循一个原则:子绝父相 (父元素使用相对定位不会影响后面的元素,子元素使用绝对定位方便移动)

【CSS第六天】光标样式、定位、水平垂直居中的方式

元素水平垂直居中的几种方式

https://juejin.cn/post/7229145941399961659

绝对定位+transform

1
2
3
4
5
6
7
8
9
.parent {
position: relative;
}
.child {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}

绝对定位+margin

适用于元素宽高固定的情况

1
2
3
4
5
6
7
8
9
10
11
12
13
14
.parent {
position: relative;
}

.child {
width: 300px;
height: 100px;
padding: 20px;
position: absolute;
top: 50%;
left: 50%;
margin-left: -170px;
margin-top: -70px;
}

绝对定位+margin: auto

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
.parent {
position: relative;
height: 500px;
background-color: skyblue;
}

.child {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
margin: auto;
width: 100px;
height: 100px;
background-color: pink;
}

flex布局

1
2
3
4
5
.parent {
display: flex;
justify-content: center;
align-items: center;
}

grid布局

1
2
3
4
5
6
7
8
9
10
11
.parent {
display: grid;
place-items: center;
height: 500px;
background-color: skyblue;
}
.child {
width: 100px;
height: 100px;
background-color: pink;
}

table-cell

1
2
3
4
5
6
7
8
9
10
11
12
13
14
.parent {
display: table-cell;
text-align: center;
vertical-align: middle;
width: 500px;
height: 500px;
background-color: skyblue;
}
.child {
display: inline-block;
width: 100px;
height: 100px;
background-color: pink;
}

清除浮动

清除浮动带来的影响:如果父元素没有设置高度,让父元素高度可以由内容撑开

定高法

给父元素设置固定高度即可

额外标签法

在父元素末尾添加新的块级子元素

1
2
3
4
5
<div>
<div style="float: left">
</div>
<div style="clear: both"></div>
</div>

overflow: hidden;

给父元素添加 overflow: hidden; 属性,实现BFC

1
2
3
4
<div style="overflow: hidden">
<div style="float: left">
</div>
</div>

单双伪元素法

给父元素添加 clearfix 类,然后利用伪元素清除浮动:

1
2
3
4
5
6
/* 单伪元素法 */
.clearfix::after {
content: "";
display: block;
clear: both;
}
1
2
3
4
5
6
7
8
9
/* 双伪元素法 */
.clearfix::before,
.clearfix::after {
content: "";
display: table;
}
.clearfix::after {
clear: both;
}

什么是BFC

BFC 的全称是 Block Formatting Context,块级格式化上下文。这是一个用于在盒模型下布局块级盒子的独立渲染区域,将处于BFC区域内和区域外的元素进行互相隔离

满足下列条件之一的元素会触发BFC:

  • html 根元素
  • 绝对定位、固定定位的元素
  • 浮动的元素
  • overflow 值不为 visible 的元素
  • 行内块元素

或者说:

  • HTML根元素
  • position 值为 absolutefixed
  • float 值不为 none
  • overflow 值不为 visible
  • display 值为 inline-blocktable-celltable-caption

BFC 的应用场景:

  1. 场景一:防止两个相邻块级元素的上下 margin 发生重叠 (上下margin合并问题)

  2. 场景二:清除浮动

  3. 场景三:实现自适应布局, 防止元素被浮动元素覆盖

参考文章:深入理解BFC

盒模型分类

https://juejin.cn/post/7255945582049198117

盒模型有两种:标准盒模型和 IE盒模型

标准盒模型

  • 宽高=内容宽高,盒子的实际尺寸=内容(设置的宽高)+内边距+边框
  • 给元素增加 padding 和 border 会撑大盒子

IE怪异盒模型

  • 宽高=内容+内边距+边框,盒子的实际尺寸=设置的宽高=内容+内边距+边框
  • 盒子的大小固定,宽高设多少就一定是多少

回流和重绘

https://juejin.cn/post/7281581471897387071

https://juejin.cn/post/7248207744087769125

1
重排一定会重绘,重绘不一定会重排

移动端适配

1
2
3
4
5
6
7
8
9
10
11
12
移动端适配的两种方式:rem适配和vw适配
rem适配:相对html根字号大小进行适配,1rem=1html根字号,一般将html根字号设为屏幕宽度的1/10
vw适配:相对视口宽度大小进行适配,1vw=1/100屏幕宽度

步骤
确定设计稿尺寸和元素大小(px)
将元素大小转为rem或vw( rem单位=px单位/html根字号 | vw单位=px单位/(1/100屏幕大小) )

补充
flexible.js是手淘开发出的一个用来适配移动端的js库,它可以根据视口宽度的大小自动调整html根字号的大小,常和rem配合使用
移动端网页经常参考的设备是ipone 6/7/8,它的尺寸是375×667px
小程序使用rpx进行适配,1rpx=1/750屏幕宽度,因为小程序设计稿大小一般为750px,我们一般不需要做转换
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 一个在 iphone6/7/8 上,大小为 68×29 的盒子
// rem适配方式
@htmlSize: 37.5rem;
.box {
width: (68 / @htmlSize);
height: (29 / @htmlSize);
background-color: pink;
}

// vw适配方式
@vw: 3.75vw;
.box {
width: (68 / @vw);
height: (29 / @vw);
background-color: pink;
}

JavaScript

本地存储的几种方式

三者都可以被用来在浏览器端存储数据,而且都是字符串类型的键值对

cookie

  • 可设置过期时间,默认关闭浏览器后失效
  • 大小只有 4KB
  • 每次请求都会携带在请求头中,作为用户已登录的标识

sessionStorage

  • 会话级别的存储,关闭浏览器或标签页后失效
  • 大小为 5MB

localStorage

  • 除非手动清除,否则永久保存
  • 大小为 5MB

cookie、localStorage 支持同源共享数据

垃圾回收机制

JavaScript内存管理

什么是闭包

闭包:在一个函数中嵌套另一个函数,内部函数中可以访问外层函数定义的变量,然后在外层函数中返回内层函数,供最外层调用

闭包 = 内层函数 + 外层函数的变量

闭包的作用:实现数据的私有化,避免全局变量污染

闭包可能引起的问题:内存泄漏,局部变量可能不会释放

解决:尽量避免函数的嵌套;执行完的变量,手动给它赋值为null,让垃圾回收机制进行回收

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 统计函数的调用次数
// 不使用闭包
// let count = 1
// function fn() {
// count++
// console.log(`函数被调用${count}次`)
// }

// 使用闭包
function outer() {
let count = 1;
function fn() {
count++;
console.log(`函数被调用${count}次`);
}
return fn;
}
// 把fn函数赋值给re
const re = outer();
re();
re();

什么是原型链

【js高级第三天】原型对象的用途、原型链、原型继承

深浅拷贝的概念、实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
直接赋值存在问题,如果把一个对象直接赋值给新对象,那么这两个对象是完全相同的,任何一个对象的修改都会影响另一个对象
浅拷贝:拷贝对象的单层属性,如果对象里面还有对象,拷贝的是对象的地址,修改任何一个对象都会影响另一个对象
深拷贝:拷贝对象的多层属性,如果对象里面还有对象,就采用递归的方式继续拷贝,深拷贝是对象的完全复制,拷贝后的两个对象不会相互影响

实现浅拷贝的方式:
- 展开运算符:先把对象展开,然后在外层使用对象的花括号接收
- Object.assign():将一个空对象和要复制的对象进行合并,得到一个新对象
- 手动实现:定义方法,循环遍历对象中的每个属性,把它添加到新对象中

实现深拷贝的方式:
- _.cloneDeep():引入lodash库,调用cloneDeep方法实现深拷贝
- JSON.parse(JSON.stringify(obj)):利用JSON序列化机制,先把对象转为JSON字符串,再转回对象就能得到一个新对象
- 手动递归:定义方法,循环遍历对象中的每个属性,把它添加到新对象中。如果对象的属性还是一个对象,就再次递归遍历这个对象,直到所有属性添加完毕

补充
JSON序列化实现深拷贝的缺点:无法拷贝对象中的方法和undefined属性,会忽略它们
1
2
3
4
5
6
7
8
9
// 浅拷贝
function getObj(obj) {
var newObj = {}
for (var k in obj) {
newObj[k] = obj[k] }
return newObj
}
let newObj1 = Object.assign({}, obj)
let newObj2 = {...obj}
1
2
3
4
5
6
7
8
9
10
// 深拷贝
function getObj(obj) {
var newObj = {}
for (var k in obj) {
newObj[k] = typeof obj[k] == 'object' ? getObj(obj[k]) : obj[k]
}
return newObj
}
let newObj = _.cloneDeep(obj)
let newObj = JSON.parse(JSON.stringify(obj))

ES6新特性

1
2
3
4
5
6
7
8
9
1.letconst关键字声明
2.对象的解构赋值语法、对象属性的简写
3.箭头函数
4.模版字符串
5.展开运算符、函数形参的默认值
6.模块化导入导出
7.Promise
8.class关键字
9.数组方法map、filter、some等

同源和跨域

1
2
3
4
5
同源策略是浏览器的一种安全策略, 所谓同源是指协议、域名、端口完全相同,不同源则跨域
解决跨域问题
- CORS跨域资源共享:在服务端响应头中添加Access-Control-Allow-Origin,设置允许
跨域访问的源地址,浏览器在收到这个响应头后,就会允许跨域访问并将响应数据返回给前端页面
- 同源访问:把前端项目和后端项目部署到同一个源下,在保证安全性的前提下直接避免跨域访问的问题

new的执行过程

1
2
3
4
1. 在内存中创建一个空对象
2. 让构造函数内部的this指向这个对象
3. 执行构造函数中的代码,给新对象添加属性和方法
4. 将新对象返回

this指向问题

1
2
3
4
5
6
7
8
一句话,this总是指向方法的调用者
- 在普通函数中,this指向window
- 在定时器中,this指向window
- 在事件处理函数中,this指向事件源
- 在构造函数中,this指向实例对象
- 在原型对象的方法中,this指向实例对象

箭头函数没有自己的this,沿用的是上级作用域的

Promise

Promise 是浏览器内置的一个对象,用来管理异步操作或异步请求,并且能够接收成功或失败的结果

Promise 对象有三种状态:

  • pending:待定状态,Promise 对象实例化完成时的状态
  • fullfilled:已兑现状态,调用 resolve 后的结果
  • rejected:已拒绝状态,调用 reject 后的结果

Promise 对象的状态一旦被更改(已兑现/已拒绝),就无法再改变

Promise.all() 静态方法 用来将多个 Promise 对象包装成一个新的 Promise 对象,以获取所有成功结果,或某一个的失败原因

Promise 实例化时是同步的,then 回调、catch 回调是异步的

async&await

async函数 是使用 async 关键字声明的函数,在 async 函数中能够使用 await 关键字

await 用来取代 then 方法,等待获取 Promise 对象成功的结果

await 只能获取成功结果,可以使用 try/catch 代码块捕获错误的结果

事件循环机制

1
2
3
4
5
6
7
8
9
10
11
12
事件循环是JS代码的一种运行机制
JS中有两种代码:一种是同步代码,一种是异步代码
同步代码是逐行执行的代码,调用时必须原地等待执行结果,才能继续向下执行
异步代码是调用后耗时的代码,它不会阻塞程序继续向下执行。每个异步代码都有一个回调函数,用来接收异步代码的执行结果。
异步代码又分为宏任务和微任务。
常见的宏任务有:事件、定时器、Ajax请求、script脚本等
常见的微任务有:Promise对象的then方法和catch方法

事件循环的执行过程是:
同步代码直接进入调用栈中执行,异步代码先进入浏览器中
等到时机成熟后,浏览器会将异步代码的回调送入相应的任务队列中(宏任务送入宏任务队列,微任务送入微任务队列)
等到调用栈中的同步代码执行完毕后,反复调用微任务队列中的代码,如果微任务队列也为空,再去调用宏任务队列中的代码

防抖和节流

1
2
3
4
5
6
7
8
9
10
11
12
为什么要防抖和节流?前端性能优化

防抖:单位时间内,频繁触发事件,只执行最后一次
使用场景:搜索框输入、表单输入校验
只要事件还在触发,防抖后的事件处理函数就不会被执行
节流:单位时间内,频繁触发事件,只执行一次
使用场景:鼠标移动、页面缩放、页面滚动
频繁触发事件,节流后的事件处理函数调用次数会大大减少

防抖就是触发事件后n秒后才执行事件处理函数,如果在n秒内又触发了事件,就会重新计时
节流就是连续触发事件,在指定时间间隔内只会执行一次函数,节流会减少函数的执行频率
工作中一般使用lodash库的debounce、throttle方法实现防抖和节流

get 和post的区别

1
2
3
4
5
6
7
8
9
10
11
get通常用来获取数据
1. 在url后面拼接参数,只能以文本的形式传递数据
2. 传递的数据量小,4KB左右
3. 安全性低, 会将数据显示在地址栏
4. 速度快,通常用于安全性要求不高的请求
5. 会在浏览器中缓存数据

post通常用来提交数据,如登录、注册
1. 安全性比较高
2. 传递数据量大,请求对数据长度没有要求
3. 请求不会被缓存,也不会保留在浏览器历史记录里

三次握手和四次挥手

1
2
3
4
5
6
7
8
9
10
三次握手是客户端跟服务器之间建立连接,并进行通信的过程     
第一次握手是建立连接,客户端发送连接请求报文,并传送规定的数据包
第二次握手是服务器端表示接收到连接请求报文,并回传规定的数据包
第三次握手是客户端接收到服务器回传的数据包后,给服务器端再次发送数据包。这样就完成了客户端跟服务器的连接和数据传送。

四次挥手表示当前这次连接请求已经结束,要断开这次连接
第一次挥手是客户端对服务器发起断开请求
第二次握手是服务器表示收到这次断开请求
第三次握手是服务器表示已经断开连接
第四次握手是客户端断开连接

http状态码

https://juejin.cn/post/7278504422425411623

1
2
3
4
5
6
7
8
9
10
1XX information(信息性状态码)       接受的请求正在处理
2XX Success(成功状态码) 请求正常处理完毕
3XX Redirction(重定向状态码) 需要进行附加操作以完成请求
4XX Client Error(客户端错误状态码) 服务器无法处理请求
5XX Server Error(服务器错误状态码) 服务器处理请求出错

补充
200 请求成功
401 身份验证失败
404 未找到
  • Title: 前端面试
  • Author: Evan
  • Created at: 2023-12-14 18:42:55
  • Updated at: 2023-12-14 18:42:49
  • Link: https://blog.wyun521.cn/web-base/前端面试/
  • License: This work is licensed under CC BY-NC-SA 4.0.
 Comments