前端面试问题总结
最近面试了很多,也有在总结自己的不足,主要是记录下之前没遇到的问题,尽量为下次面试做好准备。
避免出现公司名字,使用数字代替吧
公司1:
vue 组件通信。 props、event、vuex、eventBus,provide/inject
ref 和 reactive 区别
ref 适合独立变量属性,原始数据类型如 string,number,内部调用 reactive 实现响应式,可直接整体覆盖赋值,如替换对象,依然保持响应式
reactive 适合对象,数组,无需调用 .value,直接返回 proxy 对象,常用表单对象,只修改内部属性,不重新赋值的情况
vuex 和 pinia 使用中的区别。
vuex Api→ mutations/actions/getters,pinia Api→ state/getters/actions
pinia 原生支持 Ts,vuex 需要插件支持
vuex 必须通过 mutation 修改 state,pinia 可直接修改 state
keep-alive 的使用场景
标签页切换,表单填写状态,列表-详情页面滚动状态和过滤状态等,避免复杂组件重复渲染
一般放在 keep-alive 组件内部,属性有 include, exclude, max 限制最大缓存实例数
css 样式污染。
scope 添加 data-v-随机id
生成唯一类名
手动命名
沙箱机制
git merge rebase、reset revert。答出使用场景和区别
事件循环机制。答出常见的宏任务和微任务以及循环顺序,
promise 异步方法被 catch 后 会继续执行 finally
【代码题】
获取数组深度
/**
* 获取数组的深度
* @param {Array} arr - 要检查的数组
* @returns {number} 数组的深度(最外层为1)
*/
function getArrayDepth(arr) {
// 如果不是数组或数组为空,深度为0
if (!Array.isArray(arr) || arr.length === 0) {
return 0;
}
// 递归计算每个元素的深度
const depths = arr.map(item => {
if (Array.isArray(item)) {
return getArrayDepth(item);
}
return 0;
});
// 返回最大深度 + 1(当前层级)
return Math.max(...depths) + 1;
}
公司2:
React 区别 Vue
React 优点
JSX 语法特点
公司3:
toRef 和 toRefs 区别
toRef 是转换单个属性,参数为
toRef(obj, key)
toRefs 是转换整个对象,直接解构赋值
{ a, b } = toRefs(obj)
reactive 解构陷阱,
reactive
的陷阱:reactive
的最大问题是解构会破坏响应性。这是因为它返回的是一个 Proxy 对象,解构出来的属性是普通的值,不再与 Proxy 关联。必须配合toRefs
才能安全地解构。vue Router 路由守卫
全局 beforeEach,afterEach 参数 to from next
内部 beforeEnter 参数也是 to from next
组件内:beforeRouteEnter,beforeRouteUpdate,beforeRouteLeave
公司4:
Vue2 为何检测不到数组更新,因为重写了底层数组方法
Vue3.2 新属性 v-bind 实现 css 响应式
前端鉴权
静态鉴权:路由中 meta信息:requireAuth ,permission
路由级别:beforeEach 判断 token,获取用户权限后对比,未授权则返回403页面
动态鉴权:后端配置好相关人员对应的菜单权限
按钮级别,v-if 判断,或者封装指令
请求压缩,pako 库进行 GZIP 压缩
公司5:
项目经历,组件封装经历
console.log(a 1 && a 2 && a == 3) 为 true,写出 a 的格式
a = { i: 1, toString: function(){ return a.i++ } }
算法题:给出一个无序数组,要求返回当前数组中缺少的最小正整数,链接
公司6:
项目细节,注重底层原理
大学课程,计算机组成原理内容,专业课:数据结构,计算机组成原理,操作系统…
公司7:
项目代码部分人可见,分包,分仓
浏览器请求数量限制:6,小程序:5 → 10
vue项目分包,使用场景
公司8:
白屏时间计算,三种方式,web API,手动埋点,第三方库(Web Vitals)
const timing = window.performance.timing; const whiteScreenTime = timing.responseEnd - timing.navigationStart; // 更精确的首次绘制时间(需浏览器支持) performance.getEntriesByType('paint').forEach(entry => { if (entry.name === 'first-paint') { console.log('FP:', entry.startTime); } });
<!DOCTYPE html> <html> <head> <script> // 起始时间戳(尽量靠近<head>顶部) window.pageStartTime = Date.now(); </script> <!-- 其他资源 --> </head> <body> <script> // 首帧渲染后计算(如首屏元素出现) const firstElement = document.querySelector('.first-content'); const whiteScreenTime = Date.now() - window.pageStartTime; </script> </body> </html>
import { getFCP } from 'web-vitals'; getFCP((metric) => { console.log('First Contentful Paint:', metric.value); });
白屏优化:
网络层面:cdn,dns 解析,减少重定向
资源层面:压缩图片,服务器启用 brotli
Content-Encoding: br
, 资源预加载,link 使用 rel:preload 属性,资源异步加载:async渲染层:骨架屏,服务端渲染SSR,优化DOM层级
代码层面:路由动态引入,keep-alive
公司9:
项目难点,亮点
稳定性,未来发展方向,
日常学习网站,极客时间,MDN,stack Overflow,算法网站等,博客园,优秀博客,github
公司10:
同一个项目,分业务范围功能差异打包,如各区域/厂商的差异化开发 → 路由方案判断传入参数
接上,大屏项目就是如此,通过配置环境env,区别处理各项目的差异化功能及内容
组件封装经历,说了轮播图表组件,视频播放组件
从输入网址到展示网页全流程
HR 问日常,稳定性(自己的项目是否还在继续做),裸辞原因
公司11:
provide,inject 数据 不会同步修改,可以包裹 computed 或者使用 setup 语法(组合式写法)或者直接返回方法,把this 也返回去
qiankun 了解程度,如果不使用微前端,实现微前端功能
可以使用 iframe,单独写个页面引入路由
table 大量数据处理:
虚拟滚动 vitrual-scroll 可视窗口渲染
不需要更新,v-once
需要更新,v-memo 缓存
懒加载,分页等
箭头函数没有自己的this,指向外层非箭头函数的对象作用域,定义时即确认this,后续无法改变
Map 和 对象的区别:
Map 键值可以是任意类型,对象的键值只能是字符串或 Symbol
Map 有 get,set,has,delete等方法,Map 通过 size 获取长度,对象只能Object.keys().length
JSON 支持对象,不支持 Map,需要先进行序列化为Array 或其他格式
公司12:
扩展接口和插件机制,虚拟键盘,密码加密
vue23区别,跨域问题,性能优化各方面
公司13:
线上内存溢出如何调试,线上性能问题处理
线上去除打印内容,UglifyJsPlugin