前言
2024年了,互联网的寒意似乎并没有减退,市场行情看起来还是很不友好样子~
身边的朋友都在说道,今年行情很差,苟住要紧;各位也都被动的越来越卷了,上头让你加班时,再也没有那时到点就下班跑路的气魄了😭
耳闻不如一试,投了几家约了面试,试了下水,看看情况如何🤓
准备
虽说,是想试个水看下外面市场情况,但是该准备的还是要准备的,毕竟机会是留给有准备的人,推荐打算面试的同学还是要多准备准备😀
- 基础的东西(简单来说八股文还是要懂的,红宝书和掘金多刷刷,网上很多)
- 项目亮点,能拿的出手的东西(证明你的优势,为什么不选别人而选你?项目难点、技术博客、开源贡献、star很多的开源项目等都可以)
- 以往工作回顾总结(很重要,面试官需要知道你做了什么?能做什么?擅长什么?一定要复盘总结,提炼精华)
- 个人简历(个人信息 --> 教育经历 --> 工作经历 --> 专业技能 --> 项目经历 ,推荐这个👉 一个优秀的前端工程师简历应该是怎样的?)
- 算法(准备仓促,刷的不多,建议至少刷个100道左右,能抽象总结出思路,才算出效果;推荐这个👉前端算法面试常考题目解析)
本篇文章不过多叙述如何准备,着重记录目前市场的面试情况
面试记录
简单介绍一下面试背景:
本人19年毕业,普通本科,计算机专业,4年多前端开发经验,目前投的多是一些中小厂(人员500,1000,1万+规模的都有)
根据面试内容,梳理总结了几个方向
JavaScript
- ES6的
map
和reduce
- 主要描述了使用方式和实现原理(
for
循环的相关实现)
- 主要描述了使用方式和实现原理(
- 是否使用过装饰器
- 没咋用过,结合
nestjs
简单说了下
- 没咋用过,结合
- 闭包
- 结合执行上下文和作用域链进行了描述
- 作用域与闭包
- JS的继承方式,以及它们的区别
- 大致说了几个,太细节也记不太清了,主要围绕私有属性和方法、公有属性和方法
- 说了ES6的
class
类的babel
转义实现,即组合寄生式继承 - JavaScript常见的六种继承方式
- 手写
防抖函数、记忆函数、深拷贝
Proxy
与Object.defineProperty
的用法和传参区别- 在对比说明
vue2
和vue3
的时候提到了,并顺着问了使用上的区别,传参是什么?有多少方法等
- 在对比说明
Proxy
为何要结合Reflect
使用- 需要了解
Reflect
拥有的相关属性方法是和Proxy
一一对应的,而且可以保持纯净
- 需要了解
- 如何判断
Proxy
等方法在当前浏览器是否支持 Object.defineProperty
/Proxy
接收的参数,对应的作用,区别- with 函数了解过吗?
- new的过程
TypeScript
-
TypeScript的
type
和interface
区别- 说的比较简单,就是一些博客文章里常见的区别,类型别名、类型合并、元祖等
-
TypeScript的泛型,常用泛型
- 类比js的函数进行了说明
- 几个内置工具方法
-
TypeScript的内置工具方法
- 记不清那么多,就说了几个常见的
Omit
、Pick
、Partial
、Record
、typeof
、keyof
等
- 记不清那么多,就说了几个常见的
-
类型安全
- 说了
readonly
,面试官提了typeof
,总的来说不是很清楚 - TypeScript 类型安全
- 说了
-
实现一个
type Diff<T,S> = ?
泛型,要求返回两个对象的差异(思考Equal
)tsinterface A{ name: string; age:number; } interface B{ name: string; age:number; mobile:number; } // mobile
React
- react16.8前后
class
类组件和hooks
的区别- 说明使用
class
类组件的原因,维护状态实例,存在的问题 - 说明
fiber
架构诞生的历史背景,对已有问题的优化,也就是hooks
诞生的背景
- 说明使用
- 常用hooks
- 主要介绍了常见的
hooks
和对应的使用场景 - 结合
fiber
作进一步的原理说明
- 主要介绍了常见的
- 虚拟DOM / diff算法
- 这俩可以一起分析,虚拟
DOM
的诞生背景和作用 diff
结合虚拟DOM
做更新优化等- 考虑
react
/vue
的diff
算法区别
- 这俩可以一起分析,虚拟
- class类组件
componentDidMount
中进行setState
和hooks中useEffect(()=>{setState()},[])
进行setState
的区别- 说了队列异步更新的原理,这里说
hooks
的useEffect
class
类组件记不清了
- 说了队列异步更新的原理,这里说
- redux的异步中间件实现
- 看过相关源码,忘了。。,说了
saga
的generator
- 补充:理解中间件的实现方式 => 参数注入,主要是把
dispatch
作为参数传入,在适当的时机调用
- 看过相关源码,忘了。。,说了
- react-router如何监听路由(
vue-router
)- 基本原理需要了解,内部实现
- 合成事件介绍
- 围绕
react
结合fiber
控制优化,异步更新分析
- 围绕
- react合成事件是如何对应每个事件的
- useState状态管理的实现
- 主要围绕
fiber
的双缓存说明,以及在hooks
中以链表的数据结构管理(围绕链表顺序结构说明)
- 主要围绕
- umi的插件实现机制
- 没研究过,提到了对webpack的包装以及参数注入
- umi项目下的
.umi
文件的理解- 主要围绕预构建思考了路由的动态生成维护和
dva
数据model
的维护
- 主要围绕预构建思考了路由的动态生成维护和
- dva的内部实现逻辑
- 主要围绕
rudex
、redux-saga
进行了简要说明,generator
的使用
- 主要围绕
- redux的异步中间件实现原理
- redux-thunk
- 异步更好的方案是采用
redux-saga
,其内部使用了generator
函数,可以更好的控制异步操作的执行顺序
- react创建
context
上下文的方式,参数及作用 - redux的顶层
provider
作用及原因
Vue
- vue响应式原理
- 结合
vue
的初始化过程分析Object.defineProperty()
的数据拦截,最好把整个流程说清楚,getter
依赖收集Dep
、Wacther
,setter
触发更新通知等 vue3
的proxy
说明
- 结合
- 描述了vue2和vue3的区别及实现原理、背景、优化等
- vue中如何只让一个对象的第一层为响应式?
- 提到了 Object.freeze() 方法,追问为什么
- vue双向数据绑定原理
- 结合响应式原理分析,compile解析模板指令和变量替换,绑定对应更新函数,理清
Observer
、Compile
和Watcher
三者的关系
- 结合响应式原理分析,compile解析模板指令和变量替换,绑定对应更新函数,理清
- vue如何做到监听数组的
push
等操作方法,缺陷原因- 主要就是
Object.defineProperty()
的问题,以及vue内部对数组方法进行了拦截重写
- 主要就是
- 低代码项目中拖拉拽引出的对于拖拽嵌套实现的一些问题
- 从原生方面考虑
drag
相关事件,主要在于对边界条件的判断和处理上
- 从原生方面考虑
- 如何实现组件缓存(
keep-alive
)- 粗糙的思考:强缓存组件状态(组件仍有挂载、卸载)
- 对虚拟DOM进行缓存处理,不执行相关生命周期钩子(需要结合源码)
- 聊聊keep-alive组件的使用及其实现原理
xx.vue
文件的处理过程,template模板的处理- 一开始以为是在问
createElement
构建虚拟DOM的过程,后来说明是对template字符串内容的处理,主要为正则匹配(标签元素、变量) - 思考模板中的变量是如何更新的
- 聊聊Vue的template编译
- 一开始以为是在问
- vue3的
ref
、reactive
、unref
、toRefs
的作用和区别 - vue作用域插槽 / react中相似插槽的东西
- 默认插槽、具名插槽、作用域插槽
- 延伸思考:react中类似的东西,render props
- vue中对于视图层中使用到的变量
a ? b : c
,如何更好的做到数据的响应式(b和c只会有一个被使用)
微前端
- 微前端的优缺点
- 围绕
qiankun
进行了描述,无侵入性 - 对比
iframe
,上下文数据通信的问题,DOM问题,如全局弹窗 - 什么是微前端?为什么不是 iframe?
- 围绕
- 微前端数据隔离、样式隔离
qiankun
的实现原理说了下,参考核心源码阅读了解(快照、Proxy)- 样式隔离说了子应用自定义命名前缀
- 可能是你见过最完善的微前端解决方案
- 微前端:iframe、script、npm包方式的实现和区别、好处或缺点
iframe
可以结合乾坤官网对于该实现方式的优缺点说明(Why Not Iframe)npm
包方式的实现和区别,说了版本维护、性能问题、业务问题(说了难以作为独立一个应用的问题)script
基本就和乾坤差不多了,只是没有提供一个index.html
入口(说了难以作为独立一个应用的问题)
- 微前端父子传递方法、子应用间通信、样式隔离方案
- 官方提供有
props
、globalstate
方案、也可以使用rxjs
方案 - qiankun微前端实战看这篇就够了 - Vue项目篇
- 官方提供有
- 微前端如何实现组件共享
- 主应用下静态文件访问
- Webpack联邦模块
- rxjs
工程化
- Webpack执行过程
- 围绕webpack执行过程分析,初始化参数、加载插件、使用
loader
处理非js相关文件、广播事件等
- 围绕webpack执行过程分析,初始化参数、加载插件、使用
- npm install过程
- 下载到
node_modules
目录下,更新packge.json
文件,并执行安装命令
- 下载到
- 组件库、工具库npm包发布相关配置区别
- Webpack摘要算法配合服务器实现缓存功能(hash)
- loader、plugin简述
- loader是什么,它的参数是什么?
- Webpack模块加载原理
浏览器
- 任务机制(从宏观层面理解------浏览器中JavaScript的运行机制 - 掘金 (juejin.cn))
- 地址栏输入URL发生了什么
网络
- websocket连接过程,返回数据格式,传输方式,如何断网重连
- 服务端向客服端通知的几种方式
- 单点登录
- 在触发账号密码登录逻辑后,重新生成
token
- 在触发账号密码登录逻辑后,重新生成
- 强缓存、协商缓存
- https握手过程
算法
- 有效括号,变体(LeetCode 20)
- 删除链表的倒数第n个节点(LeetCode 19)
- 无重复字符的最长子串(LeetCode 3)
手写题
-
节流、防抖
-
深拷贝
-
实现query查询,支持链式调用
点击查看代码详情
实现一个 query,支持链式调用,参数是一个数组
jsquery(arr) .where((item) => item.age > 10) .orderBy('age') .groupBy('city') .execute()
-
where方法,参数用法和 [].filter类似
-
orderBy(key,desc) 排序,desc为true时为倒序
-
groupBy(key) 分组,生成二维数组,效果如下
js[ [ { name: 'xiao', city: 'hangzhou' }, { name: 'zhang', city: 'hangzhou' }, ], [ { name: 'li', city: 'shanghai' } ] ]
-
execute 方法,只有当该方法执行的时候函数才开始执行
-
-
字符串模板替换
jsconst data = { name: 'banana', date: { year: '2024' } } const str = '这是一个{{name}}, 今年是{{date.year}}年'
-
请求并发控制
点击查看代码详情
js实现一个 scheduler 函数,满足以下要求: 1. 接收一个参数 max 控制最大并发请求量 2. 执行以下代码依次输出:2、3、1、4 // -----------------mock一些请求 const request1 = () => new Promise((resolve, reject) => { setTimeout(() => { resolve(1); }, 1000); }); const request2 = () => new Promise((resolve, reject) => { setTimeout(() => { resolve(2); }, 500); }); const request3 = () => new Promise((resolve, reject) => { setTimeout(() => { resolve(3); }, 300); }); const request4 = () => new Promise((resolve, reject) => { setTimeout(() => { resolve(4); }, 400); });
输出题
-
react异步更新输出结果
点击查看代码详情
tsxclass App extends React.Component { constructor() { super(); this.state = { val: 0, }; } componentDidMount() { this.setState({ val: this.state.val + 1 }); console.log('1', this.state.val); this.setState({ val: this.state.val + 1 }); console.log('2', this.state.val); setTimeout(() => { this.setState({ val: this.state.val + 1 }); console.log('3', this.state.val); this.setState({ val: this.state.val + 1 }); console.log('4', this.state.val); }, 0); } render() { return null; } }
-
JS作用域代码输出题
点击查看代码详情
tsxvar name = "aaa"; const obj = { name: "bbb", fn1: function () { console.log(this.name); }, fn2: () => console.log(this.name), fn3: function () { return function () { console.log(this.name); }; }, fn4: function () { return () => console.log(this.name); } }; obj.fn1(); obj.fn2(); obj.fn3()(); obj.fn4()();
-
异步,宏任务、微任务输出题
点击查看代码详情
tsxasync function async1() { console.log("async1"); await async2(); console.log("async2 after"); await async3(); console.log("async3 after"); } async function async2() { console.log("async2"); } async function async3() { console.log("async3"); } console.log("start"); async1(); new Promise((resolve) => { console.log("promise"); resolve(); }).then(() => { console.log("promise then"); }); setTimeout(() => { console.log("setTimeout"); }, 0); console.log("end");
-
一些基础代码输出题
点击查看代码详情
js// 第一题:隐式类型转换 true == 'true' // 第二题:默认值 function fn(a = 'abc') { console.log('a', a) } fn(null) fn(undefined) // 第三题:判断改代码是否会卡死页面 // 1.情况一 function fn() { console.log('abc') setTimeout(fn, 0) } fn() // 2.情况二 function fn() { console.log('abc') setTimeout(fn(), 0) } fn() // 第四题:思考while循环是否可中断 async function fn() { while (true) { console.log('开始输出') await new Promise(() => { console.log('结果') }) console.log('结束输出') } } fn() // 第五题:执行顺序问题 // 1 2**3**2 // 2 new new Fn().getName()
项目问
- 本人项目中涉及到新技术的介绍和说明(zustand、solidjs)
- 这里使用到的工具库之前写过文章,感兴趣的可以看这里
- 性能爆表的SolidJS - 掘金 (juejin.cn)
- zustand状态管理器与观察者模式 - 掘金 (juejin.cn)
- 拖拽交互的嵌套和展示位置的自动优化(是否嵌套容器的边界判断,单一组件原则,子组件根据传入的x、y渲染位置)
- 自定义图表的实现说明
- 画业务流程图
- 你说了使用的egg做的服务端渲染网站,洋葱模型了解过吗?
- 项目部署,跨域问题一般是怎么处理的?
- 智能提示编辑器,变量的控制和查找是如何处理的
项目中的功能和细节一定要做到心中有数,面试官会追着问很多细节,一定要真诚!😄
总结
技术面总的来说还算常规,不少都是常见的八股文,好好准备下还是能应对的;
当然也有一些比较犀利的面试官,问的比较刁钻,如果还只是靠背面经就不行了,你一定是有在这个过程中投入学习的,灵活使用,一定要有自己的理解。
项目非常重要,很多问题是在聊项目细节的过程中提及的,建议抽1-2天时间把项目梳理一下,包括业务流程、项目难点等,最好写下来。
对于手写题,有些方面还有待提高,建议对于常见的手写题还是要多写、多练,特别是promise这类,一定要自己手写几遍。
算法题急不来,常规的典型一定要掌握,什么双指针、动态规划、二分查找等等,没事的时候一天刷1-2题,慢慢就积累上来了,这个只靠死记硬背很难学透,在有一定的数量之后才能引起质变,还是要有那种感觉才行,要不然,看到题,脑子里就空空的,怎么解啊。多刷几题,慢慢的脑子里就有一些解题框架和思路了,方可~
尾声
本文梳理了面试中遇到的一些问题,结合之前自己总结过的文章,已经答复了一部分(已贴出链接的),对于剩余的一些问题,后面会持续输出为面试专题进行归纳(本文会持续更新,补全内容贴上专题链接),对于文中有错误的地方,或者有不同想法的同学,欢迎指出~
要说市场行情寒意,还是能感觉到一些的,目前整个前端市场面试人员很多,有的一个职位投递几十个简历都不算多的,中小厂薪资压的还蛮多的,竞争比较多,卡死在HR谈薪环节的不少。有能力的同学可以多试试大厂😅
总的来说,当下环境还是做好自己,有机会多提升下自己的水平,提高竞争力。加油也好,内卷也罢,能不能熬到下一个风口,并有能力抓住机遇,或许每个人都有自己的答案。
后续打算在这个仓库(JS-banana/interview: 面试不完全指北 (github.com))进行维护,欢迎✨star,提建议,一起进步~