前端interview(持续更新中!)

626 阅读17分钟

前端面试题,持续学习更新中!兄弟们要是遇到过什么面试题欢迎评论,还望不吝赐教!

数据类型判断

1. typeOf: 主要用来判断基本数据类型(字符串、数字、布尔...)
缺点: 检测不准确 typeOf(null) // Object   typeof([]) // Object
2. instanceof
用法: 要判断的数据 instanceof 构造原型
缺点 instanceof只有在一个全局window下才会返回true,如果有嵌入的iframe,判断就会出错!
3. 最准确的判断方法 Object.prototype.toString.call()

闭包

把一个函数当做另一个函数的返回值,那么这个函数就是闭包函数

# 闭包函数的优点:
1. 变量常驻内存 
2. 避免全局变量污染 
3. 私有成员的存在

# 闭包函数的缺点:
由于常驻内存会造成内存资源的浪费,使用不当会导致内存泄漏

SPA单页面应用

Vue项目就是单页面应用,整个项目只有一个HTML文件,通过路由来进行页面切换

# SPA优点:
1. 用户体验及交互比较流畅
2. 组件化开发易于维护
3. 减轻服务器压力
# SPA缺点:
1. 不利于SEO(搜索引擎优化) 因为收缩殷勤爬虫只会爬取HTML,而单页面应用页面是通过js生成
2. 第一次进入页面会比较慢(可以通过路由懒加载来解决)

mvc和mvvm

# mvc(Model模型)(View视图)(Controller控制器)
View接收用户行为通知Controller,Controller通知Model进行数据更改,Model通知View进行页面更新
# mvvm(Model模型)(ViewModel视图模型)(Controller控制器)
数据双向绑定,用户行为更改数据,数据可以主动触发视图更新,双向绑定通过ViewModel进行交互

computed和watch的区别

# 区别
1. computed计算属性,初始时会自动计算一次,函数值改变会重新计算
2. watch侦听属性,被侦听的数据更改,watch执行,初始化时不会立即执行(可以通过immediate:true进行配置)
3. computed会读取缓存数据,watch没有缓存

router/routes/route

1. router路由对象(可以进行页面跳转等)
2. routes路由配置 
3. route当前路由信息(包含传参等query,params)

Vue2和Vue3生命周期

# Vue2的8个生命周期
1. beforeCreate 挂在了Vue实例的方法,但是data没有挂载
2. created 挂载了data
3. beforeMount data没有渲染到页面
4. mounted data渲染到了页面
5. beforeUpdate 数据更改导致DOM更改之前
6. updated 数据更改导致DOM更改之后
7. beforeDestroy DOM销毁之前
8. destroyed DOM销毁之后
# Vue3的生命周期
Vue3删除了beforeCreate和created用setup代替,destory改为了Unmount
1. onBeforMount data没有渲染到页面
2. onMounted data渲染到了页面
3. onBeforeUpdate 数据更改导致DOM更改之前
4. onUpdated 数据更改导致DOM更改之后
5. onBeforeUnmount DOM销毁之前
6. onUnmounted DOM销毁之后

Vue2和Vue3的区别

1. Options API 和 Composition API 
   Options API在大型的项目中容易出现命名冲突和冗余代码等
   Composition API  steup方法
2. 响应式数据的绑定
   Vue2是通的是 Object.defineProperty的get和set方法进行监控属性(缺点:无法监控对象属性的增加删除)
   Vue3是通过proxy深度监控对象,能够监控对象属性的增加删除
3. Vue3打包时无用代码会被丢弃

nextTick

在下一次Dom更新结束后的回调 (比如list,每增加一行回去一下list的高度,就需要用到nextTick)

nextTick(()=>{//代码})

Vue组件传参

1. 父传子: props
2. 子传父: emit
3. 兄弟组件传参: 事件总线eventBus Vue3使用mitt插件

异步的解决方案

1. callback
2. Promise 三种状态 pending=>转换为两个状态resolve、reject
   Promise.all 多个异步执行完进行操作
3. async/await
   async可以单独使用,并且返回的是promise对象
   await(后面跟的是一个异步操作/promise)必须配合async使用,不然会报错

构造函数的new操作符

构造函数的函数名首字母大写
# new操作符做的事情
1. 创建一个对象,指向构造函数的this
2. this的__proto__(原型对象)指向构造函数的prototype(原型链)
3. 执行构造函数
4. 返回
   如果没有return或者return的都是简单数据类型会直接忽略,直接return this
   如果return的是复杂数据类型则返回的就是当前return的值

this指向及改变this指向

# this指向
1. this指的是当前代码执行的上下文,全局环境中this指向window
2. 在函数内部this指向的是调用它的那个对象(.之前的就是this)
3. 箭头函数的this指向是声明的当前上下文环境,并且不可以改变this指向
4. 普通函数的this指向是执行的时候绑定,箭头函数是声明的时候绑定的this
# 改变this指向
1. apply 改变this指向立即执行函数,参数以数组的形式写
2. call  改变this指向立即执行函数,参数逗号分割
3. bind  用法和call一样,但是改变完this指向不会立即执行,需要手动调用

对象的深拷贝和浅拷贝

# 浅拷贝
复杂数据类型的传址
# 深拷贝
完全复制一份数据一致的非统一个地址的数据
1. JSON.parase(JSON.stringify(obj))
   把对象转换为字符串再转换为对象
缺点:这种方法进行深拷贝 undefined和函数是无法拷贝的
2. 最标准的深拷贝方法是通过递归进行拷贝

数组的常用方法

1. join: array.join('符号') 将数组转换为字符串,不会改变原数组
2. split: string.split('符号') 将字符串转变为数组,返回数组

3. push: array.push('参数') 将参数追加到数组尾部,改变原数组,返回最新的数组的长度
4. pop: 删除尾部一个元素,改变原数组,返回删除的那个元素

5. unshift: array.unshift('参数') 将参数追加到数组头部,改变原数组返回最新的数组的长度
6. shift: 删除头部一个元素,改变原数组,返回删除的那个元素

7. reverse: 反转数组,更改原数组

8. sort: 排序 sort((a,b)=>{return a-b})
   默认a<b   (return 数字  <0 升序   >0 降序) 改变原数组,返回更改后的数组
9. concat: 数组拼接 array1.concat(arr2) 不改变原数组,返回拼接后的数组

10. splice: 截取/删除数组 可以接收三个参数 array.splice('开始截取的数组下标','截取的长度','被填充替换的数据') 更改原数组返回删除的数据数组
11. slice: 截取/删除数组 不跟更改原数组 array.slice('开始截取的数组下标','结束截取的数组下标(并且不包含)')

12. forEach: 遍历并操作数组,没有返回值并不会被return
13. map: 遍历并操作数组,返回一个新数组,新数组为map的return结果
14. filter: 循环过滤符合条件的数组,返回一个新的数组
15. find: 查找符合条件的元素返回,只会返回符合条件的第一个
16. findIndex: 查找符合条件的元素返回该元素下标,只会返回符合条件的第一个
17. some: 有真则真 array.some((res)=>{return el>10})
18. every: 有假则假
19. reduce: 遍历 常用来累加 array.reduce((pre,next)=>{return pre+next})

防抖和节流

# 防抖
防抖就是多次触发只有最后一次生效
常用场景如: 下拉框输入查找等避免多次请求接口
# 节流
节流就是每隔一段时间触发一次
常用场景如: 表单提交、高频的监听事件

Hash和history的区别

区别主要在于url形式上
hash: http://xx.com/#/about
history: http://xx.com/about

vue-router有三个模式history、hash和memory内存模式,其中history和hash更为常用,两者区别主要在于显示形式和部署上,hash的使用和部署比较简单,history模式的url更加美观一些,但是应用再部署时需要进行特殊的配置(web服务器需要做回退处理,否则会出现刷新页面404的问题),实际使用无论哪种模式最终都是通过监听popstate事件出发路由跳转处理。

history模式配置中最重要的就是配置 try_files $uri $uri/ /admin/index.html  通过这个配置当url地址当Nginx无法处理时就会通过try_files去尝试,如果无法解决会回退到主页来解决404问题

Vue3的新特性

1. API层面Vue3新特性主要包括 Composition API、SFC Composition API 语法糖 (script setup)、Teleport传送门、Fragments片段、Emits选项、自定义渲染器、SFC css变量、Suspense
2. 在框架层面 虚拟DMO重写、编译器优化(静态提升、patchFlags、区块...)、基于proxy的响应式系统、通过ts和模块化使得更加易于维护、自定义渲染器等。

key的作用

key的作用主要是为了更高效的更新虚拟DOM,vue在patch过程中判断两个节点是否是相同节点,key是一个必要条件,渲染一组列表的时候key是唯一标识,如果不定义key的话,vue会认为两个节点是同一个节点,这样就会频繁的去更新元素,导致整个patch的过程会变慢,从而影响性能。

localStorage、sessionStorage和cookies的区别

localStorage:不会自动清除,除非自己手动清除
sessionStorage:页面关闭自动清除 保存在服务器端
cookies:保存在浏览器端,数据大小不能超过4K, 如果没有设置过期时间cookie存储在内存中,浏览器关闭会自动清除,如果设置了时间则会存储在硬盘中,到期自动清除。cookie只能以文本的方式保存为字符串类型,安全性低。

async和defer的区别

<script defer="defer" src="static/js/main.js"></script>
这个就需要了解浏览器的运行机制,浏览器在解析html的过程中,如果遇到一个没有任何属性的script标签,就会暂停解析,先发送网络请求去获取JS脚本的代码内容,然后让JS引擎执行改代码,当JS代码执行完毕之后才会继续进行解析,这样script就阻塞了html的解析,那么假如JS脚本的网络请求的响应很慢或者执行时间过长,就会导致用户看不到页面得内容。

# async

`async` 表示异步,当浏览器遇到带`async`属性的`script`标签时,这个`script`标签的网络请求就是异步的,不会阻塞浏览器解析html,一旦当网络请求响应成功后,如果此时html还没有解析完成浏览器会直接暂停解析,先让JS引擎去执行JS代码,执行完毕之后再继续解析html。

注意:这样的话就表示`async`的执行是不可控的如果在异步的`script`标签中含有获取`DOM`元素的操作,就有可能无法获取到`DOM`元素,如果存在多个`async`,他们的执行顺序也完全依赖于网络传输的速度,谁先成功JS引擎就会先执行谁!

# defer

`defer` 表示延迟,当浏览器遇到带有`defer`的script标签时,获取这个`script`脚本的网络请求也是异步的,不会停止解析浏览器解析html。当网络请求响应成功,如果此时html还没有解析完成,浏览器并不会暂停解析去执行JS代码,而是会等待html解析完毕之后再去执行JS代码。

注意:如果存在多个有`defer`属性的script 标签,浏览器(IE9及以下除外)会保证它们按照在 HTML 中出现的顺序执行,不会破坏 JS 脚本之间的依赖关系。

Even Loop(事件循环机制)

Event Loop即事件循环,是解决javaScript单线程运行阻塞的一种机制。

事件循环机制有三个部分组成:调用栈、微任务队列、消息队列。
evenloop开始的时候会从全局一行行执行,遇到函数会放入调用栈中(放入的函数成为帧),当函数返回后会从调用栈弹出。

如果有异步操作,比如fetch\setTimeout\setInterval 会放入调用栈,再放入调用栈的同时会将里面的消息放入消息队列,等到调用栈清空之后才会执行消息队列中的内容

promise\async\await 的异步操作会加入到微任务队列中,会在调用请控制后立即执行微任务。

BFC

块级格式化上下文,它是一个独立的块级渲染区域,该区域有自己的一套渲染规则来约束块级盒子的布局,且与外部无关。

# 如何创建BFC
1. float的值不为none
2. position的值不是static或者relative
3. display的值不是inline-block、flex或者inline-flex
4. overflow:hidden (推荐用法)

# BFC解决的问题
1. BFC可以解决盒子margin塌陷
2. BFC可以阻止元素被浮动元素覆盖

常见的HTTP状态码

200: 客户端请求成功

301: 永久重定向,表示请求的资源已经永久的搬到了其他位置。
302: 临时重定向,表示请求的资源临时搬到了其他位置 
303: 临时重定向,应使用GET定向获取请求资源,功能与302一样,区别只是303明确客户端应该使用GET访问
307: 临时重定向,和302有着相同含义。POST不会变成GET
304: 表示客户端发送附带条件的请求(GET方法请求报文中的IF…)时,条件不满足。返回304时,不包含任何响应主体。虽然304被划分在3XX,但和重定向没有关系

400: 客户端请求有语法错误,服务器无法理解。 
401: 请求未经授权,这个状态代码必须和WWW-Authenticate报头域一起使用
403: 服务器收到请求,但是拒绝提供服务 
404: 请求资源不存在

500: 服务器发生不可预期的错误。 
503: 服务器当前不能处理客户端的请求,一段时间后可能恢复正常

HTTP和HPPTS的区别

1. HTTPS协议需要CA证书,费用较高;而HTTP协议不需要
2. HTTP协议是超文本传输协议,信息是明文传输的,HTTPS则是具有安全性的SSL加密传输协议;
3. 使用不同的连接方式,端口也不同,HTTP协议端口是80,HTTPS协议端口是443;
4. HTTP协议连接很简单,是无状态的;HTTPS协议是具有SSL和HTTP协议构建的可进行加密传输、身份认证的网络协议,比HTTP更加安全

link和import的区别

1. link属于html标签,而@import是css提供的
2. 页面被加载时,link会同时被加载,而@import引用的css会等到页面加载结束后加载
3. link是html标签,因此没有兼容性,而@import只有IE5以上才能识别
4. link方式样式的权重高于@import的

浏览器缓存(强缓存和协商缓存)

# 强制缓存
使用强制缓存策略时,如果缓存资源有效会直接使用缓存,不会再向服务器发起请求。
强缓存策略可以通过http头信息中的expires属性和cache-control属性两种方式进行设置。
expires属性,指定资源过期的时间,在时间内会直接使用缓存,这个时间是服务器时间,因此如果客户端时间和服务器端时间不一致会影响缓存命中的结果。cache-control属性提供了不同的字段设置,对资源缓存的控制更加精确。

# 协商缓存
使用协商缓存策略会先向服务器发起一个请求,如果资源没有发生改变则返回一个304状态,让浏览器使用本地缓存,如果资源发生了修改则使返回资源。
命中协商缓存的条件:
1. max-age=xxx 设置缓存的最大有效期,过期了
2. 值为no-cache:客户端缓存内容,但是是否使用缓存则需要经过协商缓存来验证决定

# 总结
一般情况下强缓存和协商缓存是配合使用的,当强缓存没有命中会使用协商缓存。

在浏览器地址栏输入URL地址,按下回车制后发生了什么?

1. 用户输入网址
2. DNS解析
3. TCP连接
4. 发起HTTP请求
5. 处理请求
6. 浏览器渲染
7. TCP断开连接

TCP三次握手和TCP四次挥手

# 三次握手
1. 客户端向服务器发起,告诉服务器我准备好了,请求建立连接,你也准备一下吧
2. 服务器向客户端发起,告诉客户端我准备好了,同意建立连接,你发过来吧
3. 浏览器向服务器发起,告诉服务器,我发了你接收一下

# 四次挥手
1. 客户端向服务器端发起,告诉服务器请求发送完毕
2. 服务器端向客户端发起,告诉客户端收到请求了
3. 服务器端向客户端发起,告诉客户端响应报文发送完毕
4. 客户端向服务器端发起,告诉服务器收到了响应

重绘和重排(回流)

重绘不一定需要重排,重排必然会导致重绘

# 重绘
重绘是在一个元素的外观被改变所触发的浏览器行为,浏览器会根据元素的新属性重新绘制,使元素呈现新的外观。
引起重绘的方法: 背景颜色、不透明度等改变...
# 重排
重排是当渲染树的一部分必须更新并且节点的尺寸发生了变化,浏览器会使渲染树中受到影响的部分失效,并重新构造渲染树。
引起重排的方法: 改变元素的大小或位置、添加或删除可见的DOM元素、浏览器窗口大小改变、激活css伪类等...
# 减少重绘和重排的方法
1. 避免一条条的去修改DOM元素的样式,可以直接修改DOM元素的类名
2. 避免在大量元素上使用:hover
3. 尽量减少table使用,table属性变化使用会直接导致布局重排或者重绘
4. 避免设置多层内联样式
5. 当需要对DOM元素进行一系列的操作时,可以先使元素脱离文档流,再对其进行一些列操作,然后再把元素带回文档中
# 使元素脱离文档流的方法
1. 隐藏元素,施加修改,重新显示
2. 使用document fragment在当前DOM之外构建一个子树,再把它拷贝会文档
3. 将元素元素拷贝到另一个脱离文档的节点中,修改副本,完成后再替换原始元素

css盒子模型

CSS盒模型本质上是一个盒子,封装周围的HTML元素,它包括:边距,边框,填充和实际内容

标准盒模型: 一个块的总宽度=width+margin(左右)+padding(左右)+border(左右) 
怪异盒模型: 一个块的总宽度=width+margin(左右)(既width已经包含了padding和border值)
如何设置为怪异盒模型: box-sizing:border-box