前端常见面试问题整理
学习过程中的简单记录,若问题敬请指教!文章持续更新中...
路过的朋友,可以点个赞,关注一下~~~
1. JS中的基本数据类型
- 基本数据类型:string、boolean、number、null、undefined、symbol
- 引用数据类型:object,array,function,date,RegExp
基本数据类型的数据直接存储在栈中,而引用数据类型的数据存储在堆中。
注意
顺便提一句,栈内存是自动分配内存的。而堆内存是动态分配内存的,不会自动释放。所以每次使用完对象的时候都要把它设置为 null,从而减少无用内存的消耗
2. 什么事作用域,什么事作用域链
-
作用域:规定变量和函数的可使用范围
-
作用域链:每个函数都有一个作用域链,查找变量或者函数时,需要从局部作用域到全局作用域依次查找,这些作用域的集合称作作用域链
3. 常见的宏任务和微任务都有那些?
- 宏任务:script、setTimeOut、setInterval、setImmediate
- 微任务:promise.then、process.nextTick、Object.observe
注意:Promise 是同步任务
4. 简单说一下防抖和节流
防抖:一定时间之后在执行。n秒之后再执行事件,若n秒内被重复触发,则重新计时。
节流:一定时间之内只执行一次。n秒内只运行一次,若在n秒内重复触发,只有一次有效。
使用场景
防抖:一般用在按钮点击中,比如表单提交;再有就是联想搜索中也比较常见
节流:一般用在一些 scroll 函数的事件监听上,通过事件节流来降低事件调用的频率
5. typescript 中的infer
关键字
infer主要用于推断某个复杂类型,常与 extends 和三元运算符组合使用,用于推断某个复杂类型的部分,简单的说,就是用来推导泛型参数。
使用规则
type ParamsArray<T> = T extends Array<infer P> ? P : T;
- inter 只能出现在 extends 关键字的右侧;
- inter P 可以理解成数学上的未知数 x;
- 其中 extends 关键字的作用,是用来判断 右边的类型 是否兼容 左边的泛型 T,如果兼容则返回 ? 后面的内容,否则返回 : 后面的内容。
6. typescript中的extends
关键字
extends关键字在ts中在不同场景代表的含义不一样:
- 表示继承
- 表示约束
- 表示分配(条件类型)
继承
class Animal {
say() {
console.log('say');
}
}
class Dog extends Animal {}
const dog = new Dog();
dog.say();
泛型约束
type c = <T extends { name: string }>(arg: T) => any
function fn(cb: C) {
cb({ name: '回调' });
}
fn((arg) => {
console.log(arg.name); // 回调
});
条件类型 (需要特别理解 extend在三元运算符中的含义)
type Human = {
name: string;
};
type Duck = {
name: string;
};
type Bool = Duck extends Human ? 'yes' : 'no'; // yes
/**
* 解释:Bool 的类型是yes,这是因为Human 和 Duck 的类型往前相同,或者说Human类型的一切约束条件,Duck都* 具备;需要理解的是,这个A extends B 是指类型A可以分配给类型B,而不是说类型A是类型B的子集。
*/
可参考文章地址: juejin.cn/post/722136…
7. void
和 never
区别。
void:表示空值,null 或者 undefined。
never:表示空值,不能为任何值。
8.async/await
和 Promise
什么区别?
-
都是解决异步编程的一种方式
-
Promise
的出现解决了传统回调函数导致的“地狱回调”问题,但它的语法导致了它向纵向发展行成了一个回调链,遇到复杂的业务场景,显然不美观。 -
async/await
代码简洁,使得异步代码看起来像同步代码,await的本质是可以提供等同于”同步效果“的等待异步返回能力的语法糖,只有这一句代码执行完,才会执行下一句。 -
async/await
与Promise
一样,是非阻塞的。 -
async/await
是基于Promise
实现的,可以说是改良版的Promise,它不能用于普通的回调函数。
9. 浏览器输入 URL 到渲染页面的过程。
- dns解析,获取对应的ip地址
- 根据IP地址,访问服务器
- 建立TCP连接(三次握手)
- 发送请求
- 服务器给出响应
- 浏览器得到响应的资源,并进行解析和渲染
- 断开连接(四次挥手)
10. 三次握手
三次握手 : 建立TCP连接的时候,客户端与服务器端出现的三次握手
三次握手的步骤:
- 客户端向服务器发起连接请求
- 服务器确认收到连接请求,并且向客户端发送连接请求
- 客户端确认收到服务器发送的连接请求
11. 四次挥手
四次挥手 : 是浏览器与客户端断开连接时发生的(四次)
四次挥手的步骤:
- 甲方发出断开连接的请求
- 乙方确认收到
- 乙方发出断开连接的请求
- 甲方确认收到
##12. 为什么连接是三次握手,而断开时四次挥手?
- 建立连接的时候没有数据的传输
- 断开连接的时候可能存在数据的传输
当甲方发出断开连接请求后,已方确认收到后,可能已方还有数据没有给甲方,所以已方不能立即断开连接,只能等到已方把所有的事件处理完后,才能给甲方发一个可以断开连接的请求。
13. ES6 新增的数据类型
基础类型:symbol
。
其他类型:Set类型
、Map类型
、weakSet类型
、WeakMap类型
、TypedArray类型
14. 事件循环机制
事件循环机制,是javaScript或Node为解决单线程代码执行不阻塞主进程一种机制,也就是我们所说的异步原理。
15. webpack常见的性能优化
webpack的性能优化,主要体现在三个方面:
- 构建性能:指开发阶段的构建性能。当构建性能越高,开发效率越高。
- 传输性能:重点考虑网络中的总传输量、JS文件数量以及浏览器缓存。
- 运行性能:指JS代码在浏览器端的运行速度
构建性能
- 减少模块解析
- 优化loader性能,限制loader的应用范围
- 开启多线程打包
- 热替换 (Hot Module Replacement)
传输性能
- 分包(手动分包、自动分包)
- 体积压缩
运行性能
主要是书写代码质量的高低。可以参考常见的设计模式、代码规范、最佳实践等。
16. Vue2.0 与 Vue3.0 有那些区别?
-
更小
vue2采用的是面向对象编程,vue3采用的是函数式编程。
-
更快
vue3修改了细腻dom算法,只针对变化层进行diff,而vue2是对所有的dom进行diff。
-
vue3 加强了typescript的支持
-
数据双向绑定
vue2 使用的是
definedProperty
,vue3使用的是proxy
-
多根节点
vue3是允许有多个根节点的,即template里面可以同时写多个节点并列,
而vue2只能有一个根节点,在根节点里面再去添加其他节点。
-
vue3使用的是组合式api,vue2使用的是选择式api
-
vue2是使用this,vue3取消了this
-
生命周期不一样;vue3增加
setup
...
17. webpack
和vite
,vite
为什么快?
webpack是先打包再启动开发服务器;
vite是直接启动开发服务器,然后按需编译依赖文件。
18. 上线之后 如何提示用户刷新当前页面
目前有三种解决方案(大致概念)
WebSoket套接字
,需要后端开对应的服务进行连接(不推荐)- 前端轮询获取。定时获取对应的版本信息,需要后端参与!
- 前端设置版本,生成版本号文件,触发条件获取版本号文件资源,进行比对。(触发条件一般为请求或者路由守卫)。特别注意本方法需要设置服务器禁止缓存。纯前端。
19. UDP协议有什么优点?
- 传输数据之前通信双方不需要建立连接
- 传输数据不需要维护连接状态,包括收发状态等。
- UDP数据报首部很短,只有8字节,相对于TCP的20字节首部的开销小很多
- 吞吐量不受流量控制算法的调节,只受应用软件生成数据的速率、传输带宽、信源和信宿主机性能的限制。
20. 0.1 + 0.2 是否等于 0.3,如何解决?
因为在0.1 + 0.2
实际上计算的是这两个数字在计算机里所存储的二进制
0.1 和 0.2 在进行二进制转换的时候会出现无限循环的情况。
解决方案
可将其转换为整数后进行计算,运算之后再转为小数
21.generator
函数和 async
函数有什么区别?
generator
函数是ES2015提供的异步解决方案async
函数是ES2017提供的异步函数语法,是generator
的语法糖。- 执行方式不同,
generator
执行需要使用执行器(next()等方法);async
函数自带执行器,与普通函数的执行一样。 - async 的语法语义更加清楚,async 表示异步,await 表示等待;而 Generator 函数的(*)号和 yield 的语义就没那么直接了;
22. WebPack
如何实现热更新,与vite
的热更新有什么区别?
webpack
的热更新是使用HRM(热模块替换)技术实现的,在代码变化时,通过patch的方式更新对应的模板,而vite
的热更新则是通过webSocket
和浏览器原生的API实现的,它能够更快的更新代码,并且支持更多的语言和框架。
23. 怎么看 Vue 和 React
vue是渐进式javascript框架。j渐进式框架 和 自底向上增量开发的设计是vue开发的两个概念。
react是facebook开发的用于构建用户界面的javaScript库。react主张的是函数式编程的理念,实现了q界面的高性能高效率开发,react很擅长处理组件化的页面。
相同点
-
数据驱动视图
-
组件化
-
都使用了
Virtual Dom
+Diff算法
不同点
-
核心思想不同
-
vue定位是低门槛,快速开发。主要特点:灵活易用的渐进式框架,进行数据拦截代理,对侦测数据的变化更敏感、更精确。
-
react定位是提出UI开发的新思路,用更好的方式去颠覆前端的开发模式。主要特点:推崇函数式编程(纯组件),数据不可变以及单向数据流,当然需要双向的地方也可以手动实现,比如借助
onChange
和setState
来实现。
-
-
响应式原理不同
- vue收集依赖,自动优化,数据可变。vue递归监听data的所有属性,直接修改。当数据改变时,自动找到引用组件重新渲染。
- react基于状态机,手动优化,数据不可变。需要
setState
驱动新的state替换老的state。当数据改变时,以组件为根目录,默认全部渲染,所以React中会需要shouldComponentUpdate
这个生命周期函数方法来控制。
-
组件写法差异
- vue推荐的是
template
的单文件组件格式,即html,js,css
写在同一个文件中(支持JSX写法) - react推荐的是
jsx + inline style
,也就是把HTML和CSS全部写进去javaScript中,即all in js
- vue推荐的是
-
diff算法
- vue对比节点,当节点元素相同,但是className不同,认为是不同类型的元素,删除重建。
- react则认为是同类型节点,只修改节点属性。
-
渲染过程
-
Vue可以更快地计算出
Virtual DOM
的差异,这是由于它在渲染过程中,会跟踪每一个组件的依赖关系,不需要重新渲染整个组件树。 -
React在应用的状态被改变时,全部子组件都会重新渲染。通过
shouldComponentUpdate
这个生命周期方法可以进行控制,但Vue将此视为默认的优化。
-
24. 如何选择react和Vue
在以下情况选择vue
- 最新文档和更简单的语法。
- 更小,更快,更灵活。
- 需要丰富的HTML模板,易于开发。
在以下的情况选择react
- 需要构建移动应用程序。
- 需要构建大型应用程序。
- 轻量级,易于版本迁移。
25. any、unknown、never、void区别
定义
- any:用于描述任意类型的变量,不做任何约束,编译时会跳过对其的类型检查
- unknown:表示未知类型,即表示写代码的时候还不知道具体会是怎么样的数据类型
- never:用在不存在值的类型,常用于表示永不能执行到终点的函数返回值,例如抛出的异常或者函数中执行无限循环的代码(死循环)的函数返回值类型。
- void:表示无任何类型,没有类型,例如没有返回值的函数的返回值类型
any 与 unknown 的区别
unknown 与 any 类似,但使用前必须进行断言
或守卫
never 与 void 的区别
用于函数时,never表示函数用于执行不到返回值那一步(抛出异常或死循环)的返回值类型,即永不存在的值的类型,而void则表示没有返回值,不返回或返回undefined
如何使用
- 能不用any就不用any
- 声明时如果不确定具体的类型,则可以使用unknow代替,在使用时用类型断言或类型守卫进行类型收缩
- never常用于构造条件类型来组合出更灵活的类型定义
- void 常用于表示函数没有返回值
26. async 和 defer 区别,使用 async 需要注意什么?
相同点
- 都是异步加载
script
的解决方案。
不同点
-
defer是“渲染完再执行”
-
async是“下载完就执行”。
-
如有多个defer脚本,会按照它们在页面出现的顺序加载,
-
如有多个async脚本是不能保证加载顺序的。
特别注意:async的无序性
扩展
webpack如何解决异步相互依赖的问题?
答:webpack是通过
require.Onload
方法,确保所有的chunk已经加载完,再去执行当前模块。require.Onload
方法就是把每个模块依赖的chunk
和回调都保存起来,并检查当前所有的模块,如果发现某个模块依赖的chunk都已经加载完,就执行其回调。每当某个chunk加载完,都会调用require.Onload
,以便依赖她的模块马上执行。
27. Vue 的 nextTick
是用来做什么的?它的原理是什么?
作用
- Vue中使用
nextTick
是为了获取更新之后的DOM
原理
-
nextTick本质上是对javaScript执行的事件循环机制的一种应用。简单来说就是宏任务与微任务的执行。
-
常见的宏任务有 script, setTimeout, setInterval, setImmediate, I/O, UI rendering
-
常见的微任务有 process.nextTick(Nodejs),Promise.then(), MutationObserver;
注
javaScript的执行顺序:同步 -> 异步 -> 微任务 -> 宏任务
28. Proxy 和 Object.defineProperty 区别
相同点
- 通过
数据劫持
,实现双向数据绑定
。
不同点
Object.defineProperty()
的问题有三个:
- 不能监听数组的变化
- 必须遍历对象的每个属性
- 必须深层遍历嵌套对象
Proxy
是对Object.defineProperty
缺点的弥补。
- 数组监听。
- 对象整体监听,不需要遍历每一个属性。
29. VUE3.0 做了那些方面的优化?
- **使用组合式API:**可以按照功能将代码分割开,方便维护,也方便复用。
- **使用代理proxy:**可以直接监听数组,和整个对象,无论多深的属性都可以监听到。
- **体积更小:**使用
tree-shaking
使得打包体积更小。 - **diff算法优化:**在diff算法中增加了静态标记,作用是为会发生变化的地方添加一个flag标记,下次发生变化的时候直接找到该地方进行比较。
- **静态提升:**对没有参与更新的元素,会做静态提升,只会被创建一次,在渲染时直接复用,这样可以避免了重复的创建节点。
- **事件监听缓存:**将不需要重复创建的方法单独提出,进行缓存,避免重复加载。
- **SSR优化:**如果增加的静态内容过多,就会直接使用innerHTML的方法插入,而不会一个一个的创建节点。
30. Vue2 里面 data 为什么是一个 function ?
数据隔离,避免不同组件内数据相互影响。
31. Vue2属性发生变化,视图会同步渲染吗?
不会立即同步渲染。
vue实现响应式并不是数据发生变化之后DOM立即变化,而是按照一定的策略进行DOM更新。VUE在更DOM时是异步执行的,只要监听到数据变化,Vue将开启一个队列,并缓冲在同一事件循环中发生的所有数据变更。
如果同一个watcher被多次触发,只会被推入到队列中一次。这种在缓冲时去除重复数据对于避免不必要的计算和 DOM 操作是非常重要的。然后,在下一个的事件循环tick中,Vue 刷新队列并执行实际(已去重的)工作。
32. Vue 相关的性能优化
编码阶段
- 路由懒加载
- 第三方插件按需引入
- 图片懒加载
- v-if 和 v-show 区分使用场景
- computed 和 watch 区分使用场景
- 防抖、节流应用
- v-for循环添加key,且避免同时使用v-if
- 使用keep-alive对组件进行缓存。
打包优化
- 代码、图片压缩
- 提取公共代码(避免相同资源被重复加载)
用户体验
- 骨架屏
33. 介绍一下 Vue 的主要原理
主要实现数据双向绑定。采用数据劫持结合发布者-订阅者模式的模式,通过Object.defineProperty()
来劫持各个属性的setter与getter,在数据变动时发布消息给订阅者,触发相应监听回调。来实现数据的双向绑定
34. keepAlive是什么?
keep-alive是用来缓存组件的;<keep-alive>
是Vue
中内置的一个抽象组件,它自身不会渲染一个 DOM
元素,也不会出现在父组件链中。当它包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。
如果一个组件既在 exclude 又在 include 会被缓存吗?
不会缓存。include和exclude同时出现 exclude的优先级高于include
35. 怎么把 Vue2 项目升级到 Vue3
- 第一步:创建一个新的vue3 + TS项目,安装完成基础的依赖
- 第二步:整体项目移植,目前vue3也是兼容了Options写法,这样代码结构可以暂时不做改变,后期逐步改变。
- 第三步:把vue3中已经不再支持的API和语法进行修改替换,包括过滤器filter,v-model的用法也改变了等。
- 第四部:把项目中使用到的第三方插件和UI框架替换到vue3版本,对用的用法可能也要进行修改。
- 第五步:确保项目代码编译无误之后,需要检查代码中的业务是否正确,避免对公司项目迁移造成稳定性破坏。
- 第六步:使用 TypeScript 重构 JS 代码,TypeScript 比 JavaScript 多了静态类型检查,也增加了一些新的语法,是给项目锦上添花。但是这一步会比较耗时(因为相当于修改把JS代码都要过一遍),但是项目中可以同时存在JS 和 TS,所以可以逐步替换。
36. JS中如何去重
- 数组去重:使用Set
- 对象去重:使用 filterr + Map(方法不唯一)
对象去重示例
使用filter和Map(强烈推荐)
function uniqueFunc(arr, uniId){
const res = new Map();
return arr.filter((item) => !res.has(item[uniId]) && res.set(item[uniId], 1));
}
使用reduce(一般推荐)
function uniqueFunc2(arr, uniId){
let hash = {}
return arr.reduce((accum,item) => {
hash[item[uniId]] ? '' : hash[item[uniId]] = true && accum.push(item)
return accum
},[])
37. flex:1
的含义。
flex:1即为flex-grow:1,经常用作自适应布局,将父容器的display:flex,侧边栏大小固定后,将内容区flex:1,内容区则会自动放大占满剩余空间。
原理
flex属性 是 flex-grow
、flex-shrink
、flex-basis
三个属性的缩写。
flex-grow:
定义项目的的放大比例- ``flex-shrink:`定义项目的缩小比例
flex-basis:
定义在分配多余空间之前,项目占据的主轴空间,浏览器根据此属性计算主轴是否有多余空间。相当于设置初始值
38. React hooks 和 Vue3 的 compose api 有什么区别?
-
composition api 中的 setup只会被调用一次; react hooks 中的函数会被多次调用;
-
react hooks 需要useMemo useCallback ;
-
composition api不需要保证顺序, react hooks 要保证 hooks 顺序 一致
-
ref toRef toRefs reactive 比起 useState 太繁琐了...
两者的注意事项
react hooks注意事项:
1. useState初始化, 只有第一次有效
2. useEffect 内部不能修改state
3. useEffect 可能出现死循环 ( 依赖注入是引用类型 就会这样 )
composition api注意事项:
1. 不建议和options api共用
2. 小型项目,业务逻辑简单可以用 options api, 没必要 composition api
3. composition api 属于高阶技巧了, 抽离函数 实现组件逻辑复用
39. link和script标签的加载过程中会对DOM树构建有什么影响?
<script>
标签会阻塞DOM的解析和渲染;
带src属性的<script>
标签会触发页面paint,渲染此<script>
标签之前的元素,但也有一定的条件:
- 此
<script>
标签是在<body>
中的,<head>
中的不会触发paint; - 此
<script>
标签之前的<link>
标签需加载完毕。
inline的<script>
标签不会触发页面paint,页面必须等到脚本执行完毕,且DOM Tree和CSSOM Tree解析完毕后才会渲染;
<link>
标签不会阻塞DOM的解析;
<link>
标签会阻塞DOM的渲染;
<link>
标签同时还会阻塞其之后的<script>
标签的执行。
40. 如何优化一个网站的性能
- 网站性能优化“六步法则”:一、网页内容优化;二、服务器优化;三、Cookies优化;四、 CSS优化;五、JS优化;六、图片优化。
(1)网页内容优化
1、网站尽量减少http的请求次数;
2、网站尽量减少DNS的查询次数;
3、网站尽量避免页面跳转、重定向;
4、网站尽量缓存AJax;
5、网站尽量减少DOM元素的数量;
6、网站尽量根据域名划分页面的内容;
7、网站尽量减少iframe的使用;
8、网站尽量避免404错误;
9、网站的延迟加载;
10、网站的提前加载。
(2)服务器优化
1、网站使用CDN加速优化;
2、网站添加Expires或者Cache-Control报文头优化;
3、网站采用Gzip压缩优化;
4、网站配置Etags优化;
5、网站尽早flush刷新输出缓冲;
6、网站使用GET来完成AJAX请求;
7、网站避免空的图像来源,配置图片src属性。
(3)Cookies优化
1、网站减少Cookies的大小;
2、网站内容页面选择无Cookies域名。
(4)CSS优化
1、网站把样式表置于顶部;
2、网站避免使用CSS表达式(Expression);
3、网站用代替@import;
4、网站避免使用滤镜filter。
(5)JS优化
1、网站把JS脚本置于页面底部;
2、网站使用外部JavaScript和CSS;
3、网站削减JavaScript和CSS;
4、网站剔除重复的JS脚本;
5、网站减少DOM访问;
6、网站开发智能事件处理程序。
(6)图片优化
1、网站优化CSS Spirite;
2、网站不要在HTML中缩放图像;
3、网站中的favicon.ico要小而且可缓存。
后记
本文纯仅属于个人的一些简单的见解,比较浅显,若有不妥之处还请不吝赐教!!!(☆_☆)
如果本文对你有所帮助,欢迎点赞!!!
o( ̄▽ ̄)d