面试自我反思(一次面试失败的复盘和自我反思)
下面是好好范文网小编收集整理的面试自我反思(一次面试失败的复盘和自我反思),仅供参考,欢迎大家阅读!
今天下午去了一个线下面试,笔试+技术面,这是我人生中第一次面着面着心态炸了的面试,结果非常糟糕。现在回想起来,不管是在心态上,还是在基础知识上,我都存在着很多问题。为了直面我自己存在的问题,于是有了这篇复盘文章。
笔试题复盘
下面是在笔试中我回答的不好的题目:
什么是防抖和节流,具体怎么实现
map
、forEach 和 for 的区别
React
中setState
什么时候是同步的,什么时候是异步的
如何做到监听某个组件属性更新时才去调用函数执行
说说Vue
数据的双向绑定,并说说Model
是如何改变View
、View
是如何改变 Model
的
介绍下BFC
及其应用
异步输出题:
asyncfunctionasync1() { console.log("async1 start"); awaitasync2(); console.log("async1 end");}asyncfunctionasync2() { console.log("async2");}console.log("script start");setTimeout(function () { console.log("setTimeout");}, 0);async1();newPromise(function (resolve) { console.log("promise1"); resolve();}).then(function () { console.log("promise2");});console.log("script end");复制代码
数组扁平化+排序(不能使用数组原生 api)
var arr = [[1,2,2],[3,4,5,5],[6,7,8,9,[11,12,[12,13,[14]]]],10]
回头看看,这些都是很基础的问题。下面提供上面问题的解答(部分答案来自chatGPT
)。
1.什么是防抖和节流,具体怎么实现
这两个函数都是闭包的应用,很常考。
debounce
:
functiondebounce(fn, time) { let timer = null; returnfunction (...args) { if (timer) clearTimeout(timer); timer = setTimeout(() => { fn.apply(this, args); }, time); };}复制代码
throttle
:
functionthrottle(fn, time) { let lock = false; returnfunction (...args) { if (lock) return; lock = true; setTimeout(() => { fn.apply(this, args); lock = false; }, time); };}复制代码
2.map、forEach 和 for 的区别
三者都可用于数组的遍历,其中map
更多用于将一个数组处理成另外一个数组的场景。
至于forEach
和for
的区别嘛,可以参考:有了 for 循环 为什么还要 forEach? - 掘金 ()。除了上面文章提及的内容,还有结合async/await
使用时的问题:当 async/await 遇上 forEach - 掘金 ()。
3.React 中 setState 什么时候是同步的,什么时候是异步的
在React
中,setState
有时是同步的,有时是异步的,具体取决于如何调用它。当你在 React 生命周期方法或事件处理程序中调用setState
时,它是异步的。这是因为React
将所有的setState
调用推迟到后续的更新批处理中进行,这样可以减少更新次数并提高性能。在这种情况下,React
将更新队列中的所有状态更新合并在一起,然后一次性进行 DOM 更新。
然而,在异步代码中调用setState
时,它是同步的。例如,在定时器回调函数中调用setState
,React
会立即更新状态,而不会等待批处理。
你可以使用回调函数作为setState
的第二个参数来处理异步setState
的情况。在回调函数中使用最新的状态,而不是依赖于setState
的结果。
4.React 如何做到监听某个组件属性更新时才去调用函数执行
在 React 中,你可以使用组件的生命周期方法componentDidUpdate()
来监听组件属性的更新,并在属性更新后调用函数执行。
componentDidUpdate()
方法会在组件更新后被调用,并且会传入两个参数:prevProps
和prevState
。你可以在这个方法中比较当前的属性和状态与前一个属性和状态,来确定是否需要调用某个函数。
例如,假设你有一个<Counter>
组件,它接受一个count
属性和一个onUpdate
回调函数。你希望在count
属性更新时调用onUpdate
函数,你可以在componentDidUpdate()
方法中进行比较,如下所示:
{ componentDidUpdate(prevProps) { if (this.props.count !== prevProps.count) { this.props.onUpdate(); } } render() { return<div>{this.props.count}</div>; }}复制代码
在上面的代码中,我们比较了当前的count
属性和前一个count
属性,如果它们不相等,就调用了onUpdate
回调函数。
当<Counter>
组件的count
属性更新时,React 会重新渲染组件并调用componentDidUpdate()
方法。在方法中,我们检查count
属性是否已经更新,如果是,就调用onUpdate
回调函数。
需要注意的是,在componentDidUpdate()
方法中调用this.setState()
会导致无限循环更新,因此应该谨慎使用。
5.说说 Vue 数据的双向绑定,并说说 Model 是如何改变 View、View 是如何改变 Model 的
Vue 中的数据双向绑定是通过数据劫持来实现的。Vue 会在初始化数据时,使用Object.defineProperty()
方法将数据模型中的属性转换为“响应式”的,从而在属性被访问或修改时,触发相应的更新操作。这个过程是在 Vue 实例化时进行的,因此,只有在 Vue 实例化后,才能开始双向绑定的工作。
当数据模型中的数据发生变化时,Vue 会自动更新视图。具体来说,当我们改变数据模型中的某个属性时,Vue 会遍历所有使用这个属性的视图,并且更新这些视图中对应的元素的值,从而实现了数据模型到视图的绑定。
6.介绍下 BFC 及其应用
BFC
(块级格式化上下文)是CSS
中一个很重要的概念,它是指一个独立的块级渲染区域,具有自己的布局规则。BFC 的形成需要满足一定的条件,包括:
根元素或包含它的元素的内容;
浮动元素(元素的 float
不是 none
);
绝对定位元素(元素的 position
为 absolute
或 fixed
);
行内块元素(元素的 display
为 inline-block
);
表格单元格(元素的 display
为 table-cell
,HTML 表格单元格默认为这个值);
overflow
值不为 visible
的块元素。
BFC 的应用包括:
清除浮动
在 BFC 中,浮动元素不会影响BFC
中非浮动元素的布局,因此可以用BFC
来清除浮动。通常将父元素设为BFC
,即可清除其子元素的浮动影响。
避免margin
重叠
当两个相邻的元素都处于同一个 BFC 中时,它们的垂直margin
会发生重叠,这可能会影响布局。可以通过创建新的 BFC 来避免这个问题。
实现自适应两栏布局
可以利用BFC
的特性来实现自适应的两栏布局。具体做法是,将左右两个元素都设置为BFC
,并设置宽度和浮动等属性,从而实现自适应布局。
防止元素被浮动元素覆盖
在BFC
中,浮动元素不会覆盖 BFC 中的其他元素,因此可以利用BFC
来防止元素被浮动元素覆盖。
事实上,我对这个概念了解不够深入,仅仅知道BFC
可以用来清除浮动......
6.异步输出题
asyncfunctionasync1() { console.log("async1 start"); awaitasync2(); console.log("async1 end");}asyncfunctionasync2() { console.log("async2");}console.log("script start");setTimeout(function () { console.log("setTimeout");}, 0);async1();newPromise(function (resolve) { console.log("promise1"); resolve();}).then(function () { console.log("promise2");});console.log("script end");复制代码
下面是输出结果:
script startasync1 startasync2promise1script endasync1 endpromise2setTimeout复制代码
分析:
首先输出:'script start'
然后执行async1()
函数,输出:'async1 start'
接着执行async2()
函数,输出:'async2'
由于async2()
函数中没有异步操作,因此直接返回,继续执行async1()
函数
在async1()
函数中遇到await async2()
,此时async1()
函数被挂起,等待async2()
函数执行完毕
执行new Promise()
,输出:'promise1'
执行console.log('script end')
,输出:'script end'
然后执行resolve()
,接着执行.then(),输出:'promise2'
async2()
函数执行完毕,async1()
函数继续执行,输出:'async1 end'
最后执行setTimeout()
,输出:'setTimeout'
主要难点在于,await
后面的代码相当于创建了一个新的微任务执行。
7.数组扁平化+排序(不能使用数组原生 api)
首先是扁平化:
constisArray = (arr) => Object.prototype.toString.call(arr) === '[object Array]'functionflatten(arr) { let res = for(let i = 0; i < arr.length; i++) { if(isArray(arr[i])) res = [...res, ...flatten(arr[i])] else res = [...res,arr[i]] } return res}复制代码
然后是排序(简单写个冒泡):
functionsort(arr) { let tmp = nullfor(let i = 0; i < arr.length; i++) { for(let j = i + 1; j < arr.length; j++) { if(arr[i] > arr[j]) { tmp = arr[i] arr[i] = arr[j] arr[j] = tmp } } }}复制代码
在面试过程中,由于我是非常抵触直接手写代码的,所以涉及到手写代码的题都没写。当然,在面试中也给面试官教育了,也起了一些口头冲突。回头想想,自己实在是心浮气躁,情商也很低。
面试过程复盘
关于面试,其实这次和面试官的交流谈不上愉快,基本我回答他的一个问题,他的回复都是“你的答案并不是我想听到的,我想听到的是xxx而不是xxx”。作为一个仅仅工作一年多的普通菜鸡前端,我也自知手头项目确实乏善可陈,不过因为之前面试没有遇到过这种场面,所以这次面试我面到一半心态就开始炸了,以至于到后面闹了一些不愉快。
下面先提一下聊项目过程聊到的一些点:
请求统一封装:
聊了axios
的拦截器处理,以及取消请求的方法
问AbortController
的底层逻辑实现,回答不上来(详细的解答参考:中断操作:AbortController学习笔记 - zhoulujun - 博客园)
webpack
优化:
我提了使用swc-loader
来增加编译速度,面试官觉得不行,说swc
不够稳定不能上生产。
说我没有提到tree-shaking
(Webpack 5
内部有关于Tree-shaking
的一些处理如scope hoisting
,不过我寻思着我们聊的是我做了啥呀......)
说我没有提到他想听到的点,如用Webpack
做微前端之类的东西,事实上,我只研究了webpack
在项目构建层面的东西,这个自然是说不了。
业务开发方面:
问了表单是怎么封装的,我提了封装了一个能根据js
对象配置去生成表单的组件(事实上也没啥技术含量)。面试官不满意了,说他希望听到关于JSON Schema
的应用以及低代码平台的内容。
问了项目中有没有复杂的表单,虚拟表格实现过吗,这个因为没做过也没回答上来。
问了如何实现表单,我就回答了一下Antd
表单是怎么实现的,不过还是不满意,说不是自己写出来的东西
问了如何处理有关联关系的表单项(提了使用Antd
的useWatch
被批了,说只会调库不会自己实现)
在这个难熬的过程和面试官也聊了一些东西,他的意思是他想招做低代码的(岗位jd压根就没写......),然后我也提了下我的看法,因为我目前遇到的场景确实少,以业务开发为主,自然对这些东西接触有限,之后就给批评了。结合前面笔试写的不好的情况,面试官也直接跟我说面试不通过了。在面试过程中由于我心态炸了,回答问题也是有些不耐烦,最后也被面试官指出了面试态度有问题。至此,一场失败的面试结束了。
面试过后,我觉得自己确实问题很大,也在BOSS
上托HR
向面试官道了个歉。
总结和教训
离职到现在已经有两个月了,由于行情确实不大行,面试机会非常少。这阵子我的心情都是处于一个很down的状态,个人的性格变得有些烦躁易怒,甚至发展到线下笔试都有不耐烦没有写完题的情况。这次的面试算是一个教训,告诉我必须要调整好自己的心态,至少在应对面试这件事上,一定要抱以敬畏和学习的态度去面对,而不是心浮气躁自以为是。
其次是关于面试八股文的问题,八股文里面很多手写题,有些功能我用api很快实现就不管了,实际上自己也不确定如果不使用这些api自己会不会写。然后还有对笔试的抵触问题,这个也是我要去改变的一个点。现在前端面试的话笔试真不少,还要用纸写代码的,所以自己平时得在纸上多练练。
除了这些现有的问题,还有一些对自己项目经历以及未来规划的思考。项目的亮点从何挖掘,如何让自己的项目更加具有深度,当然这些我目前还没有太好的答案,只能说走一步看一步了。