目录
- 前言
- 一,算法篇
- 1.1 平拍数组
- 1.2 括号匹配
- 1.3 打家劫舍
- 1.4 删除最少使字符串平衡
- 1.5 爬楼梯
- 二,数据结构篇
- 2.1 二叉树
- 2.2 链表
- 三,HTML篇
- 3.1 H5新的语义标签
- 3.2 href和src
- 四,CSS篇
- 4.1 居中
- 4.2 父元素塌陷解决
- 4.3 外边距塌陷
- 4.4 CSS3盒子模型、怪异盒子模型
- 4.5 CSS三角
- 4.6 CSS响应式实现方法
- 4.7 CSS预处理器
- 4.8 CSS选择器和优先级
- 4.9 CSS定位
- 4.10 回流和重绘
- 4.11 link和@import的区别
- 五,js篇
- 5.1 事件循环
- 5.2 本地存储
- 5.3 js的new发生了什么
- 5.4 js改变this指向
- 5.5 js原型链
- 5.6 js实现防抖和节流
- 六,计网篇
- 6.1 http
- 6.2 http1.0和http2.0区别
- 6.3 http和https的区别
- 6.4 强制缓存和协商缓存
- 6.5 浏览器中输入一个url会发生什么
- 6.6 post和get请求区别
- 6.7 options请求--跨域预检
- 6.8 跨域及解决跨域
- 6.9 身份验证
- 6.10 web攻击
- 6.11 浏览器存储
- 6.12 oAuth认证
前言
这是一篇关于春招的面试面经,涵盖了我整理的大部分面试考题。在春招结束后发出,希望能帮助到需要的朋友。
由于面试的题目会比较杂,这里不标注问题的来源,只给它们做一个简单的归类。分为以下几个部分:算法、HTML、CSS、JS、Vue、计算机网络、代码题目、性能优化、脚手架。
一,算法篇
算法,考的比较多的是动态规划,也有数据结构的应用。
1.1 平拍数组
// 平铺对象
let obj = {
a: 1,
b: 2,
c: 3,
d: {
e: 4,
f: 5
}
}
let showObject = (obj) => {
for(let i in obj) {
if(obj[i] instanceof Object) {
showObject(obj[i])
} else {
console.log(obj[i])
}
}
}
showObject(obj)
// 平铺数组
let arr = [1, 2, 3, [4, 2, 4, [3, 3, 3]]]
let arr1 = []
let showArray = (array) => {
array.forEach((item) => {
if(Array.isArray(item)) {
showArray(item)
} else {
arr1.push(item)
}
})
}
showArray(arr)
console.log(arr1)
1.2 括号匹配
let str = '({[]}}'
// 括号堆栈
let fn = (str) => {
// 先转化为数组
let arr = []
arr = str.split('')
// 设置一个堆栈
let arr1 = []
for(let i in arr) {
arr1.push(arr[i])
if((arr1[arr1.length - 1] == ')' && arr1[arr1.length - 2] == '(') || (arr1[arr1.length - 1] == ']' && arr1[arr1.length - 2] == '[') || (arr1[arr1.length - 1 ] == '}' && arr1[arr1.length - 2] == '{')) {
arr1.pop()
arr1.pop()
}
}
console.log(arr1.length)
}
fn(str)
1.3 打家劫舍
var rob = function(nums) {
let dp = []
dp[0] = nums[0]
dp[1] = Math.max(nums[0], nums[1])
for(let i = 2; i < nums.length; i++) {
dp[i] = Math.max(nums[i] + dp[i - 2], dp[i - 1] )
}
return dp[nums.length - 1]
};
1.4 删除最少使字符串平衡
var minimumDeletions = function (s) {
let arr = s.split("")
// 删除左侧B
let leftB = 0
// 删除右侧A
let rightA = 0
// 对应的删除次数
let dp = []
for (let i in arr) {
if (arr[i] == 'b') leftB++
if (arr[i] == 'a') rightA++
}
dp[0] = 0 + rightA
dp[arr.length + 1] = leftB + 0
for (let i = 0; i < arr.length; i++) {
if (arr[i] == 'a') {
dp[i + 1] = dp[i] - 1
} else {
dp[i + 1] = dp[i] + 1
}
}
dp.sort((a, b) => {
return a - b
})
console.log(dp)
return dp[0]
};
let s = "baababb"
minimumDeletions(s)
1.5 爬楼梯
var climbStairs = function (n) {
let dp = [] // dp[i]为还剩几步时有几种情况
dp[0] = 0
dp[1] = 1
dp[2] = 2
if (n == 1) {
console.log(dp[1])
return dp[1]
} else if (n == 2) {
console.log(dp[2])
return dp[2]
} else {
for(let i = 3; i <= n; i++) {
dp[i] = dp[i - 1] + dp[i - 2]
}
console.log(dp[n])
return dp[n]
}
}
climbStairs(5)
二,数据结构篇
2.1 二叉树
遍历二叉树
2.2 链表
三,HTML篇
3.1 H5新的语义标签
header-头部标签
nav-导航标签
content-内容标签
section-某个区域标签
aside-侧边栏标签
footer–尾部标签
3.2 href和src
href:超文本引用,用于建立文档与资源的联系,常用有link、a;
src:将所指向的资源下载并应用到当前页,常用的有script、img。
四,CSS篇
4.1 居中
1.水平居中:
/* 采用auto */
/* margin: 200px auto; */
/* 作为父亲盒子在页面水平,也可以结合定位+平移 */
/* position: relative;
left: 50%;
transform: translateX(-50%); */
/* margin配合平移 */
/* margin-left: 50%;
transform: translateX(-50%); */
文字的水平居中还可以用到text-align: center
2.垂直居中
/* position: absolute;
top: 50%;
transform: translateY(-50%); */
/* 这个方法要注意,父亲需要解决高度塌陷的问题 */
/* margin-top: 50%;
transform: translateY(-50%); */
/* flex */
/* 父亲:justify-content:center */
/* 行内元素为父亲高度 */
/* line-height: 100px; */
3.水平垂直居中
达到样式:
方法一:父亲flex布局
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
方法二:定位+位移
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
方法三:margin,这个方法父亲要防止高度塌陷
/* position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%); */
4.2 父元素塌陷解决
前提:父元素高度由子元素撑开,当子元素设置浮动,父元素高度塌陷。
原因:子元素浮动,和父元素不在一个BFC中了(浮动的元素的z-index大于父),父元素不再被子元素撑开,高度又不固定,因此塌陷。
原:
塌陷:
解决方法:
1.给父元素设置高度,但是设置高度会导致,父亲不会随着子元素高度而扩大,不建议使用;
2.添加一个空的子元素,利用clear:both清楚浮动;或者给父元素加一个伪类元素,清除浮动;
3.给父元素添加overflow: hidden;
4.3 外边距塌陷
外边距塌陷一般是因为使用了margin,尽量使用padding即可避免。
解决方法:
1.给父元素设置透明边框;
2.尽可能使用padding+盒子模型;
3.给父元素使用overflow: hidden;
4.4 CSS3盒子模型、怪异盒子模型
box-sizing来控制,content-box是默认模式:
宽度 = padding + border + 元素本身宽度
高度 = padding + border + 元素本身高度
一旦设置box-sizing为===border-box=属性,则:
宽度 = 元素本身宽度
高度 = 元素本身高度
4.5 CSS三角
先画一个这样的正方形:
css代码:
.sanjiao {
width: 0;
height: 0;
border: 100px solid;
border-color: orangered skyblue gold yellowgreen;
}
如果要上三角:
加上这三句:
border-top: 100px solid transparent;
border-left: 100px solid transparent;
border-right: 100px solid transparent;
想要什么就去掉其他,以此类推。需要注意的是,该元素的宽度应当设置为0。
4.6 CSS响应式实现方法
1.媒体查询;
2.宽度百分比高度自适应;
3.vw,vh实现;(视口长度,视口宽度)
4.flex布局;
5.栅格布局,layout布局;
6.rem,em;(rem针对根元素,em针对父元素)
4.7 CSS预处理器
scss、less写法类似。
4.8 CSS选择器和优先级
继承(*)> 类选择器(伪类选择器)> id选择器 > 行内样式 > !important
4.9 CSS定位
relative-相对定位-相对于自己的原来位置-不脱标
absolute-绝对定位-无祖先则以浏览器,有祖先以最近一级为参考-脱标大于浮动
固定定位fixed和粘性对比sticky的比对
固定定位:相对于浏览器视口固定-脱标(会挡住文档,要预留空间)
粘性定位:没滚到边界时相当于fixed,滚到边界时相当于relative,相当于relative+fixed-不脱标(不会挡住文档,无需预留空间)
4.10 回流和重绘
重绘:重新绘画,给一个元素更换亚瑟、背景。不影响页面布局,但是颜色,背景变了,就会重新渲染页面;
回流:增加或删除DOM节点,改变页面布局,就会重新构造DOM。
关系:有回流就会有重绘,但有重绘不一定会有回流。
4.11 link和@import的区别
link可以在head中用,而@import是CSS固定的样式。
link会和页面同时加载,@import会等页面加载完再加载。
link支持使用JS去控制DOM改变样式,@import不支持。
五,js篇
5.1 事件循环
这里重要的是顺序,因为在面试中常考。
同步优先,异步时机到运行;
异步分为宏任务、微任务。微任务优先宏任务;
微任务种类:nextTick优先Promise
宏任务种类:setTimeout、setInterval、setImmediate
这里注意new Promise(()=<{})是构造函数,是同步的,但是.then是异步的,且setImmediate比其他定时器先执行。
5.2 本地存储
分为localStorage和sessionStorage。localStorage是永久的,除非手动删除;sessionStorage当浏览器删除其删除。
5.3 js的new发生了什么
创建一个空对象
把构造函数中的prototype单独拿出,创建一个对象,让新的对象的this指向这个单独拿出的原型对象;
5.4 js改变this指向
call: obj.fn.call(obj1, str1, str2…)
是把obj的fn方法的this指向改为了obj1,并以str1,str2作为fn的参数;(自动调用)
apply: obj.fn.apply(thisArg, [argsArr])
是把obj的fn方法的this指向改为了obj1,并以argsArr数组中的每一项作为参数;(自动调用)
bind: obj.fn.bind(obj1, str1, str2…)
是把obj的fn方法的this指向改为了obj1,并以str1,str2作为fn的参数;(手动调用)
5.5 js原型链
5.6 js实现防抖和节流
防抖:多次点击,仅响应最后一次;
节流:高频触发,规定时间内,只执行第一次
防抖实现:
let btn = document.querySelector(".btn")
let timeout = null
btn.addEventListener("click", async () => {
// 删除定时器
clearTimeout(timeout)
timeout = setTimeout(() => {
alert("111")
}, 1000)
})
节流实现:
// 节流,规定时间内,只触发第一次
let btn1 = document.querySelector(".btn1")
let flag = true
btn1.addEventListener("click", () => {
if(flag) {
alert('222')
flag = false
setTimeout(() => {
flag = true
}, 1000)
}
})
六,计网篇
6.1 http
超文本传输协议,用于从服务器与浏览器通讯,是一种应用层协议,基于TPC/IP通信协议来传递数据;
HTTP1、HTTP2均为TCP实现;HTTP3基于UDP实现。
6.2 http1.0和http2.0区别
http1.0的每个请求都需要建立一个新的TCP连接,请求结束后立即关闭。而http2.0引入多路由服用技术,允许在同一个TCP连接上发送多个请求和响应;
头部压缩,http2.0压缩了请求头和响应头,加强了传输效率;
http2.0服务器可以在客户端请求之前主动推送相关资源,提高页面加载速度;
6.3 http和https的区别
1.https协议需要申请证书,需要花钱;
2.http是超文本协议,信息明文传输,https则会进行加密;
3.端口不一样;
4.http连接是无状态的,https协议是SSL+HTTP构建的加密传输,有身份认证和其他玩过协议,比http协议更安全;
6.4 强制缓存和协商缓存
强制缓存,由服务器去设置,仅针对get请求。缓存的内容放在客户端。如果下次发起请求,这个内容没有过期,则可以从客户端中直接拿到。
协商缓存,第一次请求资源,服务器会对返回的资源以及资源标识,下次请求时,比对资源标识,如若一致则返回状态码304,不用返回资源,如果不一致,则会返回资源和新的资源标识。
6.5 浏览器中输入一个url会发生什么
分两种情况
第一次请求url,会先判断客户端有没有缓存,因为没有,所以会发起get请求,但是在发起get请求之前,需要建立http连接,会先进行三次握手,确保服务器和客户端都能够正常收发内容。发起get请求,服务器返回数据,客户端接收数据之后想要关闭连接,这个时候会进行四次挥手,四次挥手结束,整个过程也随之结束,浏览器此时可以渲染页面。
如果有缓存,则也需要先建立其http连接,然后发起get请求。发起get请求后服务器会返回状态码304,不会给客户端返回数据,客户端从缓存中拿到数据,然后渲染页面。
6.6 post和get请求区别
1.用法上,get请求经常用于获取数据,post用于发送数据;
2.长度上,get请求对参数长度有一定限制,post请求用于发送请求;
3.安全性上,get请求一般会在url后携带请求参数,post请求的参数存储在body中。因此get请求会更加安全;
4.get请求的内容存在缓存(强制缓存和协商缓存),post请求没有;
5.get请求可以在历史记录中看到,post不行。
6.7 options请求–跨域预检
在发起一个需要跨域的请求时,服务器会先向浏览器发起一个跨域预检请求。如果服务器支持跨域请求,则会接着发起get或者post请求(发起正式的http连接),如果不支持,则cors会返回失败。
6.8 跨域及解决跨域
说起跨域,就要聊到同源策略。同源策略,针对于两个url源,说的详细些,可以用于浏览器和服务器在发起请求之前的规则统一。
同源策略:两个url,如果它们的id,域名,端口号相同,则称它们同源;其中一个不同,则不同源。
浏览器向服务器发起请求,服务器传输数据给浏览器,要遵循同源策略。如果不遵循,则会跨域。
接下来介绍跨域请求的解决方式和其中的原理。
方式一:Jsonp。jsonp利用的是,script标签可以不遵循同源策略获取外部资源,只能用作前端的get请求。
方式二:cors。这个就需要前端去联系后端,后端设置服务器的响应头解决问题;
方式三:proxy正向代理。在前端创建一个虚拟服务器,其域名各方面跟前端保持一致。因为同源策略只针对浏览器,不针对服务器,服务器与服务器之间是可以直接发送信息。因此前端发起请求,与自己的服务器对接(不存在跨域),正向虚拟服务器与后端服务器对接(不遵循跨域),拿到请求后,代理服务器再传回数据,解决跨域;
方法四:Nginx反向代理,与正向原理类似。
6.9 身份验证
身份验证的三大块:session、cookie、token。
都用于维持用户登录状态信息。
一般情况下,用户第一次登陆网站,网站会为其开辟一个session空间,并给用户传回信息session_id。用户存储在浏览器的cookie中,下次登陆携带session_id,服务器拿到之后会进行比对,找到属于用户的session空间。
经常会考,session和cookie的区别:
1.session存储在服务器中,而cookie存储在浏览器中;
2.cookie的存储大小有一定限制,而session的存储空间相对较大;
3.cookie因为存储在浏览器中,可以通过抓包等手段获取,安全性不如session。
token的好处:
1.cookie不允许跨域访问,token可以;
2.token在服务端不需要存储session机制,因为token包含了所有登陆用户的信息,只需要在客户端的cookie或者本地存储状态信息;
6.10 web攻击
1.xss攻击
恶意穿插链接,点击该链接,加载脚本文件,可能会出现token和cookie等信息的泄漏;(反射型)
访问某个链接时,携带自身的cookie和token,传给后端。(存储型)
2.csrf攻击
用户登陆信任网站,新人网站返回session_id并产生cookie在用户的浏览器中;
用户在没有退出A的情况下,访问危险网站B。B要求访问第三方站点A,发起一个请求。而这个请求,会携带着原本的cookie。A接收到了cookie,根据用户请求达成协议,
6.11 浏览器存储
分为localStorage(永久存储)和sessionStorage(短暂存储)。两者使用方法类似,不过sessionStorage仅在当前会话下有效,关闭页面或者浏览器后被清楚。
6.12 oAuth认证
分为四种:
授权码认证、客户端认证、密码认证、隐式授权认证、刷新密钥。