#### 20230626前端大佬的面试筛出的问题,做了份答案。希望各位能用的上。顺祝各位早日上岸。
## 正则
### 涉及正则的 函数
1. search(yourRegexpOrString);
定义:检索字符串中与指定的子字符串或正则表达式相匹配的子字符串。
其他说明:该方法将忽略"g"标志和正则对象的lastIndex属性(即总是从开头找起),返回找到的第一个字符的位置,如果未找到返回-1。
2. match(yourRegexpOrString);
定义:在字符串内查找一个或多个与正则表达式匹配的字符串,返回一个对象。(忽略laseIndex属性)
其他说明:若没开启"g"标志,将只查找第一个匹配的字符串,返回一个对象,包含下标0、index、input,其中下标0等价于index,input是String的引用;开启"g",返回一个数组,数组的length是匹配的字符串个数,每个元素是每个匹配的起始字符位置。
3. replace(yourRegexpOrString,placementString);
定义:用于在字符串中用一些字符替换另一些字符,或替换一个与正则表达式匹配的子串。
其他说明:如果没有"g"标志只会替换一次,并且如果参数是字符串而不是正则对象始终替换一次。
4. split(yourRegexpOrString[,howMany]);
定义:把一个字符串分割成字符串值的数组。
其他说明:是arr.join(separatorString)反操作,如果传入"",则每个字符都将会被分隔到数组。howMany指定返回数组的个数。
## HTML、CSS、JS
### 1、浏览器页面渲染流程,说完后会问到重排重绘区别
#### 1.1 浏览器页面渲染流程
0. 渲染引擎首先通过网络获得所请求文档的内容
1. 解析HTML文件,构建 DOM Tree
2. 解析CSS,构建 CSSOM Tree(CSS规则树)
3. 将 DOM Tree 和 CSSOM Tree合并,构建Render tree(渲染树)
4. reflow(重排):根据Render tree进行节点信息计算(Layout)
5. repaint(重绘):根据计算好的信息绘制整个页面(Painting)
#### 1.2 重排重绘区别
##### 1.2.1 定义
重绘: 重绘是一个元素外观的改变导致的浏览器行为(例如改变visibility,outline,background等属性),浏览器会根据元素新的属性呈现新的外观;
重排:重排是DOM元素被js触发某种变化,渲染树需要重新计算。浏览器对DOM 树进行重新排列;这便是重排。排列完成之后重新绘制元素则是重绘。
##### 1.2.2 操作
常见的触发重排的操作:
DOM元素的几何属性变化
DOM树的结构变化(例如节点的增减、移动)
获取某些属性(例如offsetTop,offsetLeft,offsetHeight,offsetWidth,clientWidth,clientHeight等)
改变元素的一些样式(例如调整浏览器窗口大小)
##### 1.2.2 两者的区别
重绘不会带来重新布局,并不一定伴随着重排.
##### 1.3 为什么要使用 虚拟 DOM
1、操作 DOM 会导致浏览器频繁的出现页面的回流和重绘,⾮常耗性能
2、手动操作 DOM 还是比较麻烦的,要考虑浏览器兼容性问题
3、相对于 DOM对象,js对象处理起来更快,而且更简单,通过 diff算法 对比 新旧vdom 之间的差异,可以 批量的、最⼩化的执行 dom操作,从而提高性能
4、虚拟DOM 进行频繁修改,最终一次性比较并修改 真实DOM 中需要改的部分,最后在 真实DOM中 进行排版与重绘,减少过多 DOM节点 回流与重绘损耗
5、使用 虚拟DOM 改变了当前的状态不需要立即的去更新 DOM 而且更新的内容进行更新,对于没有改变的内容不做任何操作,通过前后两次差异进行比较
6、虚拟DOM 可以实现跨平台渲染,服务器渲染 、小程序、原生应用都使用了 虚拟DOM
7、虚拟 DOM 可以维护程序的状态,跟踪上一次的状态
总之:
虚拟DOM 就是为了解决浏览器性能问题而被设计出来的
若一次操作中有 10 次更新 DOM 的动作,虚拟 DOM 不会立即操作 DOM 而是将这 10 次更新的 diff 内容保存到本地一个 JS 对象中
最终将这个 JS 对象一次性 attch 到 DOM 树上,再进行后续操作,避免大量无谓的计算量
所以:
用 JS 对象模拟 DOM 节点的好处是,页面的更新可以先全部反映在 JS 对象(虚拟 DOM )上
操作内存中的 JS 对象的速度显然要更快,等更新完成后,再将最终的 JS 对象映射成真实的 DOM,交由浏览器去绘制
### 2、CSS动画,transform与animate的区别等
#### 2.1 动画状态不同
1.transform过渡只有开始和结束两种状态;
2.animation有开始,过程,结束多种状态;
#### 2.2 动画触发方式不同:
1. CSS的transition需要借助别的方式来触发, 比如CSS的状态选择器(如:hover)或 借助JavaScript来触发 。
2. animation 不但可以使用上面的方式触发, 更重要的是可以自动触发 。
#### 2.3 功能点(属性)不同
animation 控制动效上要比 transition 强,因为它具备一些控制动效的属性,比如“播放次数”、“播放方向”、“播放状态”等。
#### 2.4 transform和animation的相同点
1. 从整体来看,animation 和 transition 想做的事情都是一样, 通过控制属性变化的过程也, 实现动画; 都是立足于控制本身 dom 的 css 属性变化过程, 来实现动画的视觉效果。
2. 他们都有“持续时间”、“延迟时间” 和“时间缓动函数”等概念,这些都是用来控制动效的效果。
### 3、上下居中、flex、栅格化、定位、BFC及应用、主题切换
#### 3.1 水平居中
1. 水平居中:
text-align:center
2. flex 布局
#### 3.1 上下居中
1. 上下居中文字
line-height: 容器高度
2. 非文字的上下居中
top: 50%
margin: 容器一半高度 0 0 容器一半宽度;
3. 使用浮动
float:left;
clear:both;
4. 上下垂直居中
padding:10px 0
5. flex
display:flex;
align-items:center;
6. transform:translate();加一半减一半居中 与第二条相似
position: relative;
left: 50%;
top: 50%;
transform: translate(-50%,-50%);
#### 3.2 Grid
#### 3.2 Flex
##### 3.2.1 定义
flex布局是一种布局模型,经常被称之为flexbox,使用flex布局之后,他会给子元素提供强大空间分配和对齐能力。
flex的优点就是避免不灵活的布局形式,创建更多种布局模式供你选择,解决了子元素的对齐和分布与 响应式等问题。缺点是只能依靠自身的布局模式,稍有变化则无法改变。
##### 3.2.2 总结
用于容器的属性:
display:flex 指定flex布局
flex-direction 主轴的排序(主轴方向),默认值row
flex-warp:nowarp 项目在容器中是否换行显示,常用之warp
justify-content 主轴的对齐方式
align-items交叉轴的对齐方式(一般用于单轴线)
align-content多轴线对齐方式
用于项目的属性:
order:0项目的排序
flex-grow:0放大规则,默认0,不放大
flex-shrink:1 收缩规则,默认1,缩小;0,不缩小。
flex-basis:200px 指定主轴长度尺寸,不允许负值,默认值auto,优先级比主轴的尺寸高
flex集合写法,放大,缩小,初始尺寸,默认0 1 auto。flex:1指放大,flex:0 0不放大不缩小
#### 3.3 栅格化
1. 容器
2. 行
3. 列
#### 3.4 定位
一、静态定位:static
静态定位是元素的默认定位方式,无定位的意思。它相当于border里面的none,不要定位的时候用。
特点:按照标准流特性摆放位置,它没有边偏移,在布局时我们几乎不用。
二、相对定位:relative
特点:相对于自己原来在标准流中位置来移动的,原来在标准流的区域继续占有,后面的盒子仍然以标准流的方式对待它。
三、绝对定位:absolute
特点:绝对定位是元素依据最近的已经定位的父级元素来进行移动,不占用原来在标准流的位置
若父元素没有定位,则以浏览器为准定位(Document 文档)
四、固定定位:fixed
固定定位是绝对定位的一种特殊形式: 如果说绝对定位是一个矩形那么固定定位就类似于正方形
特点:
1. 不占位置
2、跟父元素没有任何关系,单独设置位置
3、不随滚动条滚动
五、定位要点——子绝父相
子级元素是绝对定位,父级元素要用相对定位,即所谓的子绝父相
#### 3.5 BFC及应用
##### 3.5.1 BFC
块格式化上下文(Block Formatting Context,BFC) 是 Web 页面的可视化 CSS 渲染的一部分
根元素(<html>)
浮动元素(元素的 float 不是 none)
绝对定位元素(元素的 position 为 absolute 或 fixed)
display 为 inline-block、table-cells、flex、grid...
overflow 值不为 visible 的块元素(hidden、auto、scroll)
##### 3.5.2 应用
1. 可以避免外边距重叠 ( 把两个div包裹在两个不同container容器中,用over-hidden触发container的BFC)
2. 清除浮动
2. 避免重叠
#### 3.6 主题切换
方法1:定义全局的CSS变量
方法2:切换已定义好的css文件
方法3:切换顶级CSS类名 (需使用css处理器,如sass、less等)
### 4、深浅拷贝、promise、防抖节流、es6新特性、事件循环、websocket长链接、闭包、数据存储、es6数组新方法 等这些都是目前js的基本问题,一般公司都会拿出来几个
#### 4.1 深浅拷贝
1. 浅拷贝,指的是创建新的数据,这个数据有着原始数据属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值。如果属性是引用类型,拷贝的就是内存地址
2. 深拷贝开辟一个新的栈,两个对象属完成相同,但是对应两个不同的地址,修改一个对象的属性,不会改变另一个对象的属性。
手搓深拷贝-递归、type of 判定引用数据类型、for循环、回调function
````JavaScript
function deepClone(obj) {
//判断obj是数组还是对象.
var objClone = Array.isArray(obj) ? [] : {};
//进行深拷贝的不能为空,并且是对象或者是"object"
if (obj && typeof obj === "object") {
for (key in obj) {
if (obj.hasOwnProperty(key)) {
if (obj[key] && typeof obj[key] === "object") {
objClone[key] = deepClone(obj[key]);
} else {
objClone[key] = obj[key];
}
}
}
}
return objClone;
}
````
#### 4.2 promise
##### 4.2.1 定义
是异步编程的一种解决方案,注意一下三点
1. 链式操作减低了编码难度
2. 代码可读性明显增强
3. 状态一旦修改将不或改变。(即 resolve() reject(),先执行先生效,后续不改变)
##### 4.2.1 状态
. pending(进行中)
. fulfilled(已成功)
. rejected(已失败)
##### 4.2.2 实例
. then()
. catch()
. finally()
##### 4.2.3 构造方法
. all() 当所有Promise任务是resolve结果才是resolve--也就是执行then里面的回调,只要有一个任务reject则就会执行catch里面的回调,执行时间是所有任务中执行时间最长的那个任务所对应的时间
. race() 执行结果就是最先改变状态的promise任务的状态,无论是resolve还是reject,那个先改变状态,整个任务的执行时间就是对应的那个成功任务所对应的时间
. any() 捕获任意一个先成功执行的Promise任务,那个先成功,整个任务的执行时间就是对应的那个成功任务所对应的时间
. allSettled() allSettled方法接收一组promise实例作为参数,包装成一个新的实例。只有等所有的实例都返回结果,才会结束。返回的结果不论成功失败,状态总是fulfilled,不会是失败。
. try()
. reject()
. resolve()
. catch()
#### 4.3 防抖节流
定义
节流: n 秒内只运行一次,若在 n 秒内重复触发,只有一次生效。场景:验证码,防点击按钮,王者技能
防抖: n 秒后在执行该事件,若在 n 秒内被重复触发,则重新计时。场景:获取输入框内容,王者回城
一个经典的比喻:
想象每天上班大厦底下的电梯。把电梯完成一次运送,类比为一次函数的执行和响应
假设电梯有两种运行策略 debounce 和 throttle,超时设定为15秒,不考虑容量限制
电梯第一个人进来后,15秒后准时运送一次,这是节流
电梯第一个人进来后,等待15秒。如果过程中又有人进来,15秒等待重新计时,直到15秒后开始运送,这是防抖
##### 4.3.1 防抖
````javascript
function debounce(func, wait) {
let timeout;
return function () {
let context = this; // 保存this指向
let args = arguments; // 拿到event对象
clearTimeout(timeout)
timeout = setTimeout(function(){
func.apply(context, args)
}, wait);
}
}
````
##### 4.3.2 节流
````javascript
function debounce(func, wait) {
let timeout;
return function () {
let context = this; // 保存this指向
let args = arguments; // 拿到event对象
clearTimeout(timeout)
timeout = setTimeout(function(){
func.apply(context, args)
}, wait);
}
}
````
#### 4.4 es6新特性
#### 4.5 前端常用的存储数据的方式有2种
1.本地存储:(localstorage、sessionstorage、cookie)
2.Vuex存储:(state、getter、mutations、action、modules)
1. vuex存储在内存;
2. localstorage(本地存储)则以文件的方式存储在本地,永久保存;
3. sessionstorage( 会话存储 ) ,临时保存。
4. localStorage和sessionStorage只能存储字符串类型,
( 对于复杂的对象可以使用ECMAScript提供的JSON对象的stringify和parse来处理。)
##### 4.5.1 Vuex和本地存储的区别:
1、实质的区别
vuex存的是状态,存储在内存,localstorage是浏览器提供的接口,让你存的是文件,以文件的形式存储在本地
2、应用场景
vuex用于组件之间的传值,localstorage则主要用于页面之间的传值
3、永久性
当刷新页面时,vuex存储的值会丢失,localstorage不会
4、响应式
localstorage无法做到响应式,vuex可以绑定数据响应式。
使用vuex容器存储数据时,可以配合localstorage(sessionStorage)来存储到本地,实现持久化数据
注意: localStorage.setItem(key, String), set的值必须是字符串,如果你的数据是对象都需要先行转换(JSON.stringify(xxx)),取出时localStorage.getItem(key),取出后的字符串可以通过JSON.parse(xxx) 转回对象。
##### 4.5.2 Cookie,localStorage,sessionStorage区别?
特性 Cookie localStorage sessionStorage
数据的生命期 一般由服务器生成,可设置失效时间。如果在浏览器端生成Cookie,默认是关闭浏览器后失效 除非被清除,否则永久保存 仅在当前会话下有效,关闭页面或浏览器后被清除
存放数据大小 4K左右 一般为5MB
与服务器端通信 每次都会携带在HTTP头中,如果使用cookie保存过多数据会带来性能问题 仅在客户端(即浏览器)中保存,不参与和服务器的通信
易用性 需要程序员自己封装,源生的Cookie接口不友好 源生接口可以接受,亦可再次封装来对Object和Array有更好的支持
#### 4.6 事件循环
##### 4.6.1 Event Loop
是JavaScript或Node为解决单线程代码执行不阻塞主进程一种机制
##### 4.6.2 同步任务、异步任务(宏任务、微任务)
整体的script(作为第一个宏任务)开始执行的时候,会把所有代码分为两部分:“同步任务”、“异步任务”;
同步任务会直接进入主线程依次执行;
异步任务会再分为宏任务(进入宏任务队列) 和 微任务(进入微任务队列)。
当主线程内的任务执行完毕(主线程为空时),会检查微任务的任务队列,如果有任务,就进入主线程全部执行,如果没有就从宏任务队列读取下一个宏任务执行;
每执行完一个宏任务就清空一次微任务队列,此过程会不断重复,这就是Event Loop;
##### 4.6.3 栗子
```javascript
new Promise((res)=>{
console.log(1)
setTimeout(()=>{
console.log(2)
})
res()
}).then(()=>{
console.log(3)
})
//输出结果: 1 -> 3 -> 2
// setTimeout的定时器回调函数是异步执行的,而Promise中的resolve函数res()是同步执行的。
// 当Promise的状态变为resolved后,.then中的回调函数会被添加到微任务队列中等待执行。由于
// 微任务队列中的任务会在主线程的同步任务执行完毕后立即执行,所以数字3会在数字2之前被打印出来。
```
### 5、还有一些更简单的比如基本数据类型,let const var区别(或者说变量提升),改变this指针,跨域,作用域等等
#### 5.1 基本数据类型
1. 引用数据类型 Function、Array、Object
2. 基本数据类型 Number、String、Boolean、Undefined、null、symbol
3. Undefined、Null 的区别
主要区别在于undefined表示尚未初始化的变量的值,而null表示该变量有意缺少对象指向。
#### 5.2 let const var区别
var声明的变量既是全局变量,变量提升,允许重复;
let命令所在的代码块内有效,块级作用域,不允许重复;
const声明一个只读的常量,块级作用域,不允许重复,不允许修改;
变量提升: 变量提升的作用是在代码执行之前提前声明变量,避免变量在代码执行时被意外修改
#### 5.2 修改 this 指向
call 参数列表 立即执行
apply 参数数组 立即执行
bind 参数列表 返回函数
#### 5.3 跨域
1. devServer proxy
2. nginx 反向代理
#### 5.4 作用域
1. 全局作用域 var
2. 函数作用域
3. 块级作用域 let const
### 6 function 与 箭头函数 区别
1. 字面意思:function 箭头
2. this指向:function的 this指向调用该函数的对象,如果没有直接指定就是window;箭头函数不会创建自己的 this ,始终指向箭头函数声明时所在作用域下的 this 值,也就是从箭头函数所在作用域的父层继承this。
3. 箭头函数:没有constructor, 不能用作构造器(不能被new)
4. 箭头函数:没有__proto__,
5. 箭头函数:不绑定arguments。普通函数中可以使用 arguments 对象获取函数的所有参数。
6. apply、call、bind中使用箭头函数,不能改变this指向
## VUE相关
### 1、vue2与vue3区别以及vue3的组合式api好处
#### v2/v3区别
##### 1.数据劫持方式不同
1.vue2的底层原理是基于 Object.defineProperty封装的一种发布订阅模式,利用它的get和set方法对对象的属性进行监听
2.vue3是基于es6的proxy封装的发布订阅模式
数据劫持方式的不同是的v2和v3有何区别
Object.defineProperty只能监听对象的属性并且不能监听动态添加的属性。es6的proxy可以监听一切。
##### 2.v-if和 v-for优先级问题 (不会就别说这条)
v-for的优先级⾼. 因为v-for的时候我们才开始渲染dom元素,这个v-if还⽆法进⾏判断.
v-for和v-if不能同时使⽤,我们可以通过标签,⽐如div或者template标签来进⾏包裹,把v-if写到包裹的标签上⾯(写到v-for外⾯
##### 3.vue3中废除了filter
##### 4.生命周期钩子函数的不同
v2 beforeDestroy 废弃了 v3 beforeUnmount
v2 destroyed 废弃了 v3 用 unmounted
##### 6.router (不会就别说这条)
##### 7.API
vue2是选项api 需要什么选项就直接写什么选项
vue3是组合api 所有的代码都写在setup里边 需要什么就要import引入什么
##### 8.Vue3默认使用懒加载
##### 9.重构虚拟DOM
### 2、v2/v3生命周期、watch与computed区别、slot插槽、v2/v3的vif与vfor优先级区别、nextTick
#### 2.4 nexTick
#### 2.4.1 定义
在下次 DOM 更新循环结束之后执行延迟回调。
#### 2.4.2 场景
1. 在 Vue 的数据变化后,想要执行一些操作,确保操作在 DOM 更新后执行,例如在数据变化后操作 DOM 元素、触发子组件的方法等。
2. 在 Vue 的生命周期钩子函数或自定义的方法中,需要等待 DOM 更新完成后执行一些操作。
### 3、权限控制 —— 这问题很多,一般都是问按钮权限的控制,我一般都是答全局指令
钩子函数: 指令定义函数提供了几个钩子函数(可选):
bind: 只调用一次,指令第一次绑定到元素时调用,用这个钩子函数可以定义一个在绑定时执行一次的初始化动作。
inserted: 被绑定元素插入父节点时调用(父节点存在即可调用,不必存在于 document 中)。
update: 被绑定元素所在的模板更新时调用,而不论绑定值是否变化。通过比较更新前后的绑定值,可以忽略不必要的模板更新(详细的钩子函数参数见下)。
componentUpdated: 被绑定元素所在模板完成一次更新周期时调用。
unbind: 只调用一次, 指令与元素解绑时调用。
### 4、axios封装、用过的ui组件,用过的echarts图表等
### 5、v2/v3 diff算法、v2/v3 双向绑定原理、动态添加路由(addRoute,也是和权限相关一起问)
#### 5.1 diff 算法
#### 5.1.1 diff定义
diff 算法是一种通过同层的树节点进行比较的高效算法
虚拟 dom 渲染成真实 dom 的新旧 VNode 节点比较
#### 5.1.1 diff整体策略为:深度优先,同层比较
#### 5.2 vue双向数据绑定
vue双向数据绑定是 通过 `数据劫持` 并结合 `发布-订阅模式` 的方法来实现的。 也就是说数据和视图同步,数据发生变化,视图跟着变化,视图变化,数据也随之发生改变。
示例:
```` javascript
<input type="text">
<p></p>
<script>
window.onload = function () {
const input = document.querySelector('input') // 发布者
const p = document.querySelector('p') // 订阅者
window.data = '' // 要双向绑定的数据
Object.defineProperty(window, 'data', {
get: function() {
return data
},
set: function(value) { // 数据劫持,订阅者函数,更新 DOM
p.innerText = value
}
})
input.onkeyup = (e) => { // onkeyuo与setter 共同形成事件中心 broker
window.data = input.value // 发布数据
}
}
</script>
````
### 6、组件通信 —- 基本必问
### 7、性能优化 —- 基本必问
1.cdn、懒加载、各类loader压缩、gzip压缩、精灵图、icon转font、接口合并等等
### 8、xxs攻击以及预防(这个问题济南本地的公司没有问的,只有啥啥济南分公司可能问道)
# 写在最后的话
鸡儿的济南今年真热。
写的不全凑活着看吧,这次收获颇丰。
面试题仓库地址自己fork看着改就行,个人学习系列 20230626面试题 https://gitee.com/yiyanghuayigai/personal-learning-notes.git
先声明下不是我自己的库,我拿别人的库改的。原始库:https://github.com/febobo/web-interview
被人问的最多的就是项目经历,还好出彩的地方能说的过去。面试题要背,项目经历也要梳理一下。比如说,权限控制等等啥的,以及你做过的出彩的技术之处和项目经历。
学历加专业筛人太狠了,有公司现在都招聘985211的。
市场好转后也不知道从北上广回来的铁子们,还要不要回去?