【面试实录系列】记一次面试经历

232 阅读20分钟

Hello,大家好。

从我们今年三月份推出辅导服务以来,已经有半年了。目前是已经提供了简历辅导模拟面试以及全流程辅导这三种类型的辅导,适合不同需求的小伙伴。我们也在不断打磨辅导流程,感兴趣的同学可以通过小程序(前端面试题宝典)和PC端中的“增值服务”了解详情,或者联系小助手(微信号:interview-fe)咨询了解更多哦。

我们在辅导过程中,发现不少的同学平时背八股文背的很熟练,但是在面试时却因为知识点比较深入、紧张或者大脑断片等原因,不能很好地将自己准备的内容表达出来。

所以我们计划从今天开始,陆续给大家带来一个新的系列——面试实录,让大家看看真实的面试中,面试官是怎么一步步深入问题,以及面试者的现场表现。

面试实录

以下对话来自一次模拟面试。

面试官:你好。请问是XXX么,你这边约了一个2点的面试。我是你的二面面试官,我们现在开始电话面试。你这边先做个1~2分钟的自我介绍吧。

面试者:嗯,面试官你好,我叫XXX,在前端开发这个行业有三年的工作经验。

第一家公司是在北京,做了一个项目的话有在线教育的 SaaS 系统。主要的功能的话就是注册登录,一些相应的权限的控制,比如说是会员的话就可以看一些只有会员能看的视频,不是的话就就有一个路由的拦截,然后还有支付功能,还有一些视频播放的功能。然后还有从个人中心里更改一些自己相应的资料,还有更改账号密码这样一个功能。

另外这个项目就是 vue 的那个商城项目,这个是移动端的。包括了购物的整个流程,比如说购物车,或者是说选择收货地址管理自己的购物的一些订单,还有支付的一个功能。

接下来的话就是深圳的这家公司,然后他深圳这家公司主要就是写 React 还有 hooks 还有 TS 然后项目的话都是这些技术栈写的。然后主要就是一个面向七星门店的 ToB SaaS 系统。然后它主要的话就是包括前台的开单,给车辆添加配件,还有就是管理自己的一个采购配件的订单,还有给这些配件进行一个入库出库,或者说这个配件的走向的一个流程的记录。然后收款的话他收款的订单的话也会同步到财务的模块里。然后员工的话也可以对这个门店的员工进行一些管理,也可以给他们分配一些相应的权限。

还有一个就是这这个系统对应的一个运营后台,这个运营后台的话就是给公司内部人员去使用的。然后他主要就是为了帮客户去配置一些客户门店里他们需要的数据,然后就是就是省着客户自己去配置了。然后这样这个运营后台就是不需要登录他们的账号,就可以在这个系统上直接帮他们配置一些他们想要的数据。我的介绍差不多就是这些。

面试官:我看你之前是 vue,后来是转型做 React 这一块的。那么你讲一下常用的 hooks

面试者:react常用的 hooks, 首先就是 useState,然后这个的话就是跟那个类组件里面的那个 state 是差不多的。在前面声明那个变量的名称,然后后面就是写上那个 set 加上那个变量的名称,就可以更改那个变,调用的时候就可以更改那个变量的值。

还有就是 useEffect,这个就是相当于一个副作用的那个函数。它如果是后面这是后面就是第二个参数的话,是一个是空数组的话,它就是相当于类组件里面的那个 componentDidMount。如果那个数组里面有变量的话,它就是这个变量发生了变化,就会调用它里面的那个函数。

面试官:你刚说的这个第二个参数,这个依赖项这个参数吗?它是个浅对比还是深对比?或者我举个更具体的例子,假如这里面的一个依赖项它是个 object,然后如果我只改变这个 object 里面的某一个属性的话,会不会重新触发?

面试者:可以重新触发。

面试官:除了模拟 componentDidMountcomponentDidUpdate外,还能模拟什么吗?

面试者:还能模拟那个就是卸载的 componentWillUnmount。在那个回调里面加一个 return 然后在里面写上那个卸载清除监听一些相应的事件。

面试官:除了这两个 hooks 还有没有别的 hooks

面试者:其他的还有那个 useMemo,这个就是用作性能优化。还有就是useCallback,还有就是有一个可以用那个子组件调用那个父组件,相应的一些方法有个 useContext 什么的,就是那个hooks。

面试官:你刚才说的最后这个这个是怎么做?

面试者:这个的话就是子组件就是子组件,用那个把它给包裹起来,然后使用的话,就是父组件有一个写法,可能是我说不太清楚。

面试官:你有没有写过自定义 hooks 呢,如果有的话,能不能说一个具体的场景?

面试者:我有写过一个model,然后它的那个控制它的那个显示隐藏的那个 visual 那个变量是在它那个 models 里面去写的。然后如果说外面如果说在那个外面想要调用它的那个显示隐藏,就是用这个就行。

面试官:Ok. hooks 这一块的话,你在用的过程中有没有什么要注意的点?

面试者:hooks 的话。它就是那些 userStateuseEffect 不能写在 if/else 里面,因为它这个框架获取这个 state 的变量的时候是按照顺序去获取的,如果写在 if/else 的话,它会打乱它那个获取的顺序,然后他就会导致就是他获取的 state 出现就是错乱什么的。

面试官:有了解过他这个存储是以什么样的结构存储的吗?

面试者:存储结构的话,这个我没怎么了解过。

面试官:你说一下,父子组件通信有除了一个 hooks 有 useContent 然后还没有别的办法?

面试者:父子组件父传子直接就是那个传到标签里用 props 接收就行了。然后子传父的话就是也是那个标签里传一个 function 然后再把那个要传递的那个变量通过 callback 然后直接传递过去。

然后那个 ref 可以赋值的话,也可以用那个 ref 就是比如说给子组件绑定一个 ref 然后父组件就可以调用这个子组件的一些方法。

面试官:你最新的项目现在已经把 ts 用起来了是吧?对是本身就有的,还是说是项目中间加了。

面试者:这个的话是就是本身就用了,因为这个项目的话好像是 20 年重新写了一个,然后当时的话就有直接应用这个 TS 了。

面试官:TS 里面接口怎么去声明一个属性是非必须的。

面试者:这个不太了解。

面试官:OK ,泛型有用过吗?

面试者:泛型有用过。泛型的话就是相当于将就是一个 TS 类型当做一个参数。然后比如说它应用场景的话,比如说是一个 table 组件,然后它有两个页面都要用这个 table 组件,但是这两个页面的话里面的数据的 TS 类型是不一样的。然后在封装这个 table 组件的时候,就是用到了这个泛型。然后比如说如果说一个 table 组件用到了它,然后就是再把相应的那个类型就是当做用那个括号的形式给它传递过去。然后这样的话就是保证了这个组件的一个复用。

面试官:你在项目中我看一下有用到 Webpack 是吧?有自己搭过脚手架吗?

面试者:webpack 的话就是可我一般都是用它做一些相关的那个 loader 跟 plugin 的有一些配置有做过。

面试官:你先说下常用的 loader 吧。

面试者loader 的话就是那个有 TSlint 那个 loader,就是把那个把 TS 代码转换成 JS 。然后还有 eslint 那个 loader 就是去检查 JS 的代码,还有 CSS loader 就是加载 CSS 的,然后还有 sass loader 就是把 Sass 那个代码转换成 CSS 的,然后还有就是 babel loader 这个是把 ES6 转换成 ES5,然后还有就是 image loader 这个就是加载那个图片文件的,还有就是 file loader 这个也就是把文件输出到一个文件夹里。然后还有一些还有那个 cache loader 就是还是可以在一些性能开销比较大的 loader 前面添加了,然后它就是可以把结果缓存到磁盘里去做一个缓存的这么一个功能。然后也要常用的应该就是这些。

面试官:一个 Sass 文件会经过哪几个loader 。

面试者:Sass 的话就是有 Sass loader 然后还有 CSS loader,还有那个 style loader

面试官style loader 的作用是什么?

面试者:他就是把那个 CSS 代码那个注入到 JS 中,然后去加载CSS。

面试官:如果我要分离出来要怎么办?。

面试者:这个我不大清楚

面试官:你这个项目有写,二次封装加入token,这个是在哪里去加的?

面试者:就是在那个有一个文件就是写那个 request 然后在那里面去写一些。就是拦截接口,请那个接口的请求在里面写一些相应的封装。比如说返回 200 了是取那个 res.data 然后失败了的话再做一些相应的提示什么的。

面试官:这个 token 是加到 HTTP 的哪里。

面试者:这个问题我没明白?

面试官:就是你这个东西应该是后端给你还是你传递给后端。

面试者:这个 token 就是登录的时候后端传给我,然后反正他有的时候一些接口就是如果说他需要这个 token 的话,再把他给我的这个 token 就是存到一个全局的那个状态管理里面,然后再再传给他。

面试官:但你那你传给他是放在哪里,然后再传递给他呢?

面试者:一般就是放那个 local storage 里面, local storage 是前端的东西。

面试官:那后端是怎么拿到它。

面试者:后端的话就是就是当成做请求的时候,把它放到那个参数里面,就是传过去。

面试官:刚刚聊到 HTTP 这块,你说下 HTTP 常用的返回码。

面试者

HTTP 就是常用的状态码

  • 1XX 的话就是那个相当于就是请求。
  • 然后 2XX 的话就是 200 的话就是相当于成功。
  • 然后那个 3XX 的话就是重定向,然后比如说协商缓存的话,它会命中的话,它会返回那个304。然后 301 的话是那个永久的,而是有就是 301 跟 302 有一个是永久的那个重定向。然后有一个是临时的一个重定项,就是代表资源就是暂时被放到了那个 URL 里面。
  • 然后 4XX 的话就是那个客户端错误。比如说 400 的话可能代表着就是传递的那个参数可能是有问题的。然后 404 的话就是代一般来说就是但可能是因为接口的地址可能是有问题。
  • 然后 5XX的话就是服务器错误。500 的话可能一般是后端那个运行哪个方法或者说控制帧了,他就会报这个错误。然后 503 的话可能就是代表服务器的那个加载或者是网络一些问题。

面试官:OK,你刚刚提到协商缓存这一块。你能说一下 http 的缓存吗?

面试者:HTTP 的缓存的话主要就是有强缓存还有协商缓存。然后它判断缓存的时候它是先判断强缓存,然后如果是命中强缓存的话,它就是直接从缓存里面取。如果是如果不是强缓存的话,它再判断是不是协商缓存,它会那个判断协商缓存的时候,它会向服务器发送请求,然后服务器返回。但这个里面它会告诉那个浏览器是不是协商缓存,如果是的话,它就会去这个缓存里面取。如果不是的话,就有那个那服务端返回相应的一些资源。

然后判断强缓存的话,它有它有两个字段,一个是 expires 然后这个是 HTTP 1.0 出现的,它主要是一个时间,就是绝对时间的一个就是值,然后通过这个时间去判定这个资源是否是过期了。然后还有一个事就是那个 if more 那个 if 就是还有一个 HTTP 1.1 的时候出现的一个字段,那你叫 if 什么的,然后这个的话就是比 expires 的优先级是高的。然后也是通过那个这个字段的一个 max-age 去判断就是它是否是过期了,也是一个关于时间的一个的数字。

然后就是协商缓存的话,它也是有两个字段,就是它有四个字段去进行判断的,一个是那个 last-modified 这个是那个资源的最后更新时间。

然后还有一个是 if-modified-since,它是通过比较这两个时间去判断那个资源在两次请求之间就是有没有进行过修改。如果没有修改的话,就是判断它命中了那个协商缓存。

然后还有一个就是 ETag 跟那个 if-none-match 然后这个 ETag 是那个资源的唯一标识,然后那个然后这服务器的话就是通过比较那个头部的标识 跟那个当前资源的那个 ETag 是否一致。然后来也是判断两次请求之间是否有修改。然后然后这个两个字段的优先级是比上两个字段的优先级高的。然后如果说是通过 f5 刷新网页的时候,它会跳过强缓存,然后但是它会检查协商缓存。如果是 ctrl 加 f5 强制刷新的话,它就直接从服务器加载,就跳过了这两个缓存。

面试官:你刚才说e-tag 的优先级比 last-modified 高吗?

面试者:对

面试官:那 last-modified 是有什么问题,为什么后来又去搞一个 ETag?

面试者last-modified 它应该是先出的。然后这个我记不太清了,反正就是它是一个先出的两个字段,然后可能当时是有一些问题,然后后来又出现了这两个字段去修正那个问题。

面试官:ok,我们聊些基础的,你说一下数组常用的方法。或者你说一下数组有什么方法去重?

面试者:数组去重的话就是最简单的就是两重套循环去遍历数组。然后还有就是用那个 new Set(),就是 ES6 的一个方法,然后把那个数组放到 set 里面,然后在外面再套一层数组,然后用那个扩展运算符,然后就可以实现去重。

然后还有就是也是遍历这个数组,然后用那个 indexOf 去判断那个数组里面是不是已经有这个元素了,然后还可以用那个 filter 去重,然后还可以用 sort 去重。

然后用 sort 怎么系统用 sort 的话也就是方案的话就是进行一个排序。然后判断就是他前后两个就是是不是一样的。然后如果一样的话就是去掉。 介绍一下数组的 reduce 方法。

reduce 方法的话就是主要我主要用这个 reduce 方法可能就是做一个累加。然后它首先它是给它第二个参数给它规定一个初始值。然后第一个参数的话在那个函数里面写一些相应的操作,然后也就是类似于这个可以给它进行遍历。

面试官:如果第二个不是初始值的话,那是什么含义?

面试者:如果不是初始值的话,就不是初始值,应该默认是 0 吧。这个我记不太清,是零。

面试官:这个你下去看一下。你平时用 sass还是用 less

面试者:一般都是 sass 比较多,然后 less 的话可能在别的项目里有用。然后那个别的其他的项目我不是经常写。

面试官:能说下你用到的一些 SaaS 的特性吗?

面试者:SaaS 的特性的话就是不用写一些重复的类名,就是比如说它一个 div 里面,然后比如说还有一个那个还有一个 div 这样的话就直接在那个 div 下面再写写一个中间再写一个点 div 再括号。然后就这样可以就是累加起来去写,然后就是写写法比较方便。然后还有的话就是可以有那个变量,就是那个 $ 符,然后去规定一个变量,比如说规定一个就是系统的一个主题颜色,比如说给它规定成 red 然后如果说有需要用到这个主题色的地方的话,就直接把那个变量拿过来就可以。

面试官:有了解过的微前端这个东西吗?

面试者:微前端的话就是一些概念上的东西,我有了解过,它就是比如说一个比较庞大的项目的话,就给它分成分解成几个微应用,然后再通过那个基座给它连那个连接到一起。然后它的微前端的一个优势的话就是比如说就是它的那个可以保证它就是那个下面的一个微应用,比如说 A 跟 B 的话,它是基本上可以保证它是完全就是解耦合。那比如说应用了微前端之后,这个 A 应用可以用那个 vue3 写,然后这个微应用 2 可以就是用那个 vue 2 写,然后他们两个之间就是可以独立的进行各自的那个开发什么。

面试官:现在你就有没有了解过近几年前端一些比较火的一些技术。

面试者:近几年前端比较火的就是有有了解过,就是有那个 low-code 的,这个的话就是可以在那个这个用法的话,就是可能有一些活动页面或者说营销页面,这种页面就是应该比较简单。然后如果说过了这个活动的话,这个页面就不用了。然后这个时候就可以用那个 low-code 的去完成,就是让它自动的去生成这个页面相应的代码。或者说有什么平台,比如说可以就是让运维,让他们自己去设计这个相关的一个页面,把相应的元素都放在上,让他们自己去生成一个页面。

面试官:有了解过市面上现在有哪些这样的低代码。

面试者:这个的话就没怎么了解过,因为项目中好像也没怎么用过。

面试官:还有没有别的比较火的东西?

面试者:还有比较火的,可能就是刚才有说过的那个微前端。然后之前项目的话就是当时要重构一个项目,然后也在讨论了是不是就是需要用这个微前端。然后后来就是觉得那个项目的话中间几个模块就是可能业务复杂度、关联性太高了,然后不适合可能不适合微前端,然后最后那个方案的话就 pass 掉了。

面试官:那一开始为什么是想着用微前端,是出于什么考虑?

面试者:一开始的话就是老大那年说就是可能他们也听到了,就是为比感觉这个公司的话需要引入一些,就是可能需要引入一些新的技术。可就让我们的前端的 leader 去那个看一下,就是能不能那个在项目的重构的时候用一加微前端,然后跟我们那个下面人讨论一下。然后当时就是有这么一个那个考虑。

面试官:还有吗。

面试者:我了解到的应该就这些。

面试官:那技术面这块的,我我面的差不多了,你有没有什么想了解的?

面试者:了解的话就是想问一下那个公司现在主要是做一个什么项目,然后团队的规模人数。

面试官:公司这边的主要的业务都可能是偏向协同办公这样这一块的一个东西。然后像你刚才有提到的一个低代码平台,我们这边其实也是有研发的,还有就像流程平台,还有一些统一门户这样的一些就是都都是一些可能就是可视化去搭建这些应用页面这样的一些应用的这样的一些平台。然后规模的话刚才我提到了几个像什么低代码的平台,流程平台就都是这些规模的,前端都是 5 到 6 个人这样子。然后的话整体的话整个平台的话是有大概有五条业务线,还有一个架构部,就差不多 30 多个人这样子。

面试者:我别的要问的应该没有了。

面试官:那这个的话我这边的面试可能就先这样,然后我会跟 HR 那边去沟通一下你的情况。

面试者:好 谢谢面试官,再见。

面试官点评

通过以上的面试实录,我们可以看到,面试官提的一些问题,是逐步深入的。

但很显然,在整个面试过程中,面试者的表现并不是特别理想,有些回答是有问题的。比如 这个 token 是加到 HTTP 的哪里 这个问题,面试官很明显是想问 token 放在 cookie 中,请求时自动带上,还是放在 header 中的自定义字段中,但面试者来回说了半天,没有说到点子上。

再比如,“http 的缓存”这块,花了很大的篇幅说了自己了解的情况,完全可以进行概括,用简短的语言表达出来。

该面试者有些时候,没有把面试官往自己的亮点及熟悉的方向去引导,比如提到了解过新技术 low-code ,但又说是leader看了一下,组织讨论了一下,那么自己在其中承担了什么职责呢?有没有尝试推动方案落地呢?回答没有看到面试者的主动性,会有所减分。

整个面试,只能给这个面试者60分,属于勉强及格。