likes
comments
collection
share

记一次有趣的面试经历

作者站长头像
站长
· 阅读数 7

前两天面了一家公司,面试官小哥哥声音真的很像是刚毕业的大学生,我记得我以前刚学c语言的时候,b站上有个叫小甲鱼的up,这个面试官口音,音色都很像他,因此一听声音我就自带愉悦感,因为那个up讲课很可爱,我是最后问了才知道原来面试官是96年的,感觉面试官人很好,如果面试都这样,我觉得找工作就不会那么痛苦了

面试全程

面试官:做个自我介绍

我:面试官您好,~~

面试官:为什么选择前端

我:省略~

ps:一直不懂为什么问这个哈哈哈

面试官:css有几种元素啊

我:块级div,p,h1,table,行内块img,span,button,input,行内a,span

面试官:css常见单位

我:px, rem, em, %, vh, vw

这里我忘记了em相对于谁来着,他后面提醒我了,是相对于父元素的fontsize

面试官:css里面的方法函数你清楚吗

我:我有点疑惑,是指定义变量吗,还是媒体查询时那个区间

面试官:对,就是那个min-width啥的,还有包括那个image的url的请求地址,我就是想看看你对css的积累程度,包括你刚刚说的css变量已经很普及了,就像是那个主题色

我:对,是这样的

面试官:能介绍下盒模型吗

我:IE盒模型的自身宽度会被borderpadding挤掉,省略

面试官:你说反了,IE盒模型没有paddingborder,你可以说是border-box是向内挤压,content-box是向外挤压

我:额,对对,我也是这个意思,我表达有点问题

面试官:js数据类型有哪些

我:根据存放地址分为两大类嘛,原始,引用类型……

面试官:typeof 有几种输出值

我:思考了会儿~

面试官:你就直接说你刚刚说的那些数据类型吧

我:好,原始中除了null其余都是什么输出什么,比如number就输出number……,对于引用类型,除了function可以输出function外,其余都是object

面试官:嗯~,那可以精准判断数组的方法有哪些

我:Array.isArray,然后还有个Object.prototype.toString.call(),还有个instanceof,这个通过原型,会有点不准

面试官:那Object.prototype.toString.call()输出什么呢

我:[object array]

面试官:instanceof刚刚你说到是通过原型判断,那你能说说他的原理吗

我:就是顺着一个原型链去查找,__proto__,隐式原型,隐式原型就是构造函数的显示原型嘛,最终都是往Object去找,通过这个链进行递归

面试官:有哪些东西没有原型

我:null,这其实是个bug,因为其二进制全是0

面试官:怎么创建一个没有对象,没有原型

我:额……

面试官:不知道也没有关系,因为原型有个好处,自身找不到就去原型身上找对吧,如果可以屏蔽掉这个原型,你有什么方法

我:哦!屏蔽可以通过hasProperty

面试官:除了这个还可以通过Object.create(null)

此时面试官直接发来一张图,他还给我敲一遍哈哈,好感动

记一次有趣的面试经历

我:噢噢,对,想起来了,可以把null做参数放进去

面试官:js有个关键字this,你知道怎么判断那个this指向吗

我:有好几种,默认是指向全局嘛,函数得话就指向声明位置,箭头函数得话指向外层最近的非箭头函数,对象也有个this问题,好像叫做隐式绑定,对象里面的函数会指向对象,还有三个方法显示绑定,call,apply,bind

面试官:嗯,那三个的区别呢

我:都是改变this的指向,call接受参数是单个的,apply是通过数组的形式,bindbind,有点忘了哈哈

面试官:bind跟前面两个是有区别的,它是不执行这个函数的,然后bind好像不能扩展他的参数,我忘记了它能不能,因为它不执行,不一定能增加参数啊,我试下

这个时候面试官在敲,发来下面一张图

记一次有趣的面试经历

内心有点小开心,这个面试官人还怪好得嘞

面试官:哦!bind确实可以堆加参数,不过是显示传参,枚举传参,然后,函数当中有个概念叫做闭包,能谈谈你对它的理解吗

我:闭包就相当于会停留在调用栈中,函数执行会产生一个执行上下文在调用栈中,执行完毕正常来讲是会进行销毁的,闭包就相当于一个函数中返回了一个新的函数,这个新的函数会用到那个函数中的参数,这个时候就无法销毁,导致一个内存泄露的问题

面试官:额~回答得一点,没答到核心啊,除了return一个函数还有其他方法吗

我:额……

面试官:你要是答上来这个,就能很好理解闭包了,我先纠正下你刚刚的说法,你的说法很片面,任何函数执行上下文,在没有运行期间是没有这个概念的,函数在运行时,v8会给他创建一个函数执行上下文,这个局部作用域,return出的函数能够保持着对原函数执行上下文的引用,避免GC回收掉,对不对,那除了return一个函数,其实还有其他的方法,这边给你演示一个办法

我又笑了,我搁这来上课了哈哈哈

记一次有趣的面试经历

面试官:你看,其实不一定是return,只要是在这个执行上下文以内的函数,能够在外部被执行,都能够成称之为闭包,我直接挂在全局上不也可以,函数内部的函数没有中断对这个函数执行上下文的连接嘛就是闭包

我(内心):是,妙哉~

面试官:那你讲讲闭包在工作中有什么作用吗

我:额,作用啊,既然需要用上里面的参数,我就可能需要用上这个东西,比如时间戳,那个防抖节流……

面试官:其实你这个回答很牵强,一看就是没用过闭包,对不对,既然是在一个封闭的环境中,那么就有很多特点,可以私有化变量,只能在这个入口中修改这个变量,我给你讲个场景啊,比如你要在全局中做一个弹窗,通知,每次新的通知需要覆盖在旧的通知上面,那相当于这个z-index就要累加,那这个z-index放在哪儿呢,放在全局呢,还是在闭包呢,闭包也是挺不错的选择对不对。除了这个以外,你想要让这个函数只执行一次,once这个函数挺有名的,对不对,你就可以把这个函数放到闭包里面,给闭包增加一个私有化变量,给一个标识,执行过就直接return,没有就++,其实也是一个场景,为什么要问你这个呢,问你这个才能回答出更多的设计

面试官:js中有个异步啊,额,我有个问题想问你啊,如果说js是个单线程语言,你认同吗

我:认同啊,js设计之初就是个脚本,不需要那么多的性能,单线程性能不会太多

面试官:不对!

我: 啊?

面试官:其实语言自身是没有单线程多线程之分,语言所在运行环境内才能规定它是单线程还是多线程,js有哪些运行环境,目前你所知道的,不就是一个浏览器,一个node,那在nodejs中就是多线程的啊,它可以有子线程,包括现在浏览器有个worker,子线程,你可以去查下,也出了新api,起初设计成单线程的原因,历史原因肯定有吧,但是他出了个东西叫做任务队列的方式去解决对吧,那你讲讲这个任务队列

我:事件循环,一个event-loop先执行同步代码,然后再执行微任务,最后执行宏任务,两个异步都有相应的队列去执行,谁先入谁先执行

面试官:任务队列?你讲的太含糊了!

我:不不不,有微任务队列,和宏任务队列

面试官:宏任务,额,其实不一定是以队列的形式去执行,它没有这个明确的概念,只有微任务有

我:对,是这样的,执行一次宏任务之前会把微任务队列给清空掉

面试官:对啊,那你讲讲你了解到的微任务有哪些吧

我:很少,应该就是mutationObserver,还有Promise.then,然后nextTick?

面试官:啊,有nextTick这个东西吗

我:不好意思,那个是vue里面的哈哈,应该就是这两个吧,那个await算不算,后面的代码会被作成微任务

面试官:宏任务呢

我:比如I/O流,script标签,三个定时器,应该还有的,挺多的我记得(挠头

面试官:还有一个requestAnimationFrame,这个你知道吗

此时,面试官打字发给我

我:没听过

面试官:没听过啊,本来还想考下你这个的哈哈

我:是个新的api

面试官:很早就出了,那现在就问下vue相关的知识吧,之前java有个mvc的架构,vue自己也有个自己的架构,叫做mvvm,能讲讲mvvm

我:我不太了解这个,好像是个概念,我记得全称是model view-view model,没特意关注这个概念

面试官:学框架肯定要从设计原理来学,这都不了解?哈哈,行,我跟你讲讲,mvvm正如你所说,是这三个单词,view model就是核心,意思就是说,修改数据的时候你不需要主动去修改视图,像原来的jquery得话,query这个dom,把dom找到,vm得话,就不要找了,直接把数据响应到这个视图上,就是监听某个事件on对不对

我:哦,就是一个响应式原理

面试官:既然不知道这个,那你清楚这个响应式原理吗

我:这个清楚,像是vue3得话就是用Proxy代理嘛,其中reactive就是纯粹得用了这个东西,拦截对象,然后可以对对象有13个操作,当然简单实现,就只需要用上getset函数,分别作一个依赖收集,和依赖触发,就是像是computedwatchwatchEffect这些依赖,ref得话,就相当于用上了原生js的对象的语法,gettersetter,分别作依赖收集和依赖出发,不过ref也是可以去响应式引用类型的,因为里面做了个类型判断,如果是引用类型,就直接调用这个reactive

面试官:额,回答的……没有把核心想法说出来,其实他就是想通过一个发布订阅的模式来实现

我:对,就相当于一个发布订阅模式

面试官:不管是2的defineProperty,还是3的Proxy,都是为了劫持这个数据,实现一个订阅发布,订阅了内部的这个取名为watcher,数据发生变化了就会通知所有的这个watcher去更新update,对不对,其实更关键的讲一点,就是watcher内部有个更关键的watcher,叫做Renderwatcher,负责渲染整个dom的,我们写的template是不是会被编译成Render函数,Render函数也是个特殊的Renderwatcher,它的特殊点在于它是一个队列更新的,会进行一个合并,多次进行更新得话只会合并一次,响应最后一次的更新

我:哦!这就有点像是如今的浏览器的渲染队列,也是执行一次

面试官:嗯!watcher里面有个常用的api我看看你了解吗,就是computed计算属性知道吗,讲讲对他的理解

我:嗯,就是个计算属性嘛,监听这个数据的变化,响应式到页面上,并且有缓存机制,对性能更好点

面试官:除了缓存这个优点,还有个优点你知道吗

我:还有一个吗

面试官:yeah~~

有点可爱,完了

我:不太清楚

面试官:还有个优点叫做懒执行computed是不是传一个函数,函数就会涉及到函数会不会被调用执行,他会去判断函数什么时候需要执行

我:哦,就是判断数据源的变化去执行

面试官:除了这个还有个条件,就是数据是否被读取,要是template或者js中都没使用到这个数据,就不会去执行了,假设有个if分支下才执行变化,要是都没走到if分支里面,就压根不会执行了,这点你可能知道这个原理,但是没有深入去get这个关键点,那我想问你,你知道怎么实现这个两个特点的吗

我:应该是里面写了个effect函数吧,这个effect函数……

面试官:还effect函数呢,还扯上了里面的hook去了,不对!想想

他这个不对,语气很可爱哈哈哈哈

我:啊?

面试官:刚刚你不是回答了吗,引导过你了,闭包不是可以实现私有化的对不对,闭包有个特点,第一啊,computed会放到闭包这个环境里面,闭包环境里面有两个闭包的变量,一个-value,一个-dirty,就是一个值,后者就是标记这个值是脏值还是非脏值,如何理解这个脏值呢?它的依赖变更后不会发上去执行他,先把他标记成脏值,对不对,下次读取这个值的时候,就会先判断这个值有没有,再判断是否为脏值,如果是脏值肯定就需要重新求值了对不对,其实答案就藏在之前回答的闭包里面,私有化变量,那你想想,是不是这个原理,如果依赖发生变更了,正常的render函数肯定直接发生更新的,进行update,但是computedupdate,它直接告诉闭包里面的dirty,数值脏了,下次用这个值的时候再去判断是否读取这个值

面试官:那我再问你,生命周期啊,一个父组件A,还有一个子组件B,A的createdmounted和B的createdmounted,这个四个钩子的执行顺序

我:额,既然区分了父子关系,那么一定是父组件的created先执行,挂载得话应该不一定,应该是接着子组件的created,最后挂载的话应该是倒着来的,应该是子的挂载先,最后父的挂载

面试官:这道题就不给你答案了,自己有时间下去多研究下,你肯定写过vue,但是没有刻意去关注这个挂载,渲染顺序对吧

我:挂载肯定在渲染之前嘛

面试官:我说初始化,挂载

我:初始化肯定在挂载之前

我:对!有些可能写的比较久了,你拿来问我可能答得不全

面试官:哈哈,我刚刚问的问题,不就是你自己写的东西吗

我:像是那个生命周期,确实写过,但是没有研究过嵌套的情况

面试官:那你讲讲你的nextTick的原理吧

我:就是通过那个mutationObserver打造的,所以是个微任务,其实这个关于微任务有一定的发展史,因为浏览器的兼容问题,里面还有对应的setTimeout执行,不兼容就会去调用定时器,去模拟这个异步

面试官:其实也不是全是mutationObserver,有个优先级判断,一层层的判断下去,看你浏览器的支持度,然后你忘记说了一个重要点,就是起到一个渲染完毕的作用

这个时候他在跟我找vue3的源码,然后说了句vue3的源码不好找啊

我:哦!对,差点把这个忘说了,哈哈

面试官:git也用过吧

我:嗯嗯,git指令很多,但是平时在学校就用的那几个指令,放到暂存区等等……

面试官:我看你的项目是个小红书,小红书是个瀑布流,那你讲讲这个瀑布流怎么实现的

我:瀑布流可以使用别人写的~

面试官:你引用别人?我要你自己造

我:这应该需要涉及到拿到图片的宽高,然后一系列计算,致使尽可能的填满空间,应该挺复杂的吧

面试官:其实还好哈哈,有时间再跟你讲!好了,我这边没什么问题了,你有什么问题吗

我:你应该挺年轻的吧哈哈哈,感觉你学识很多,听声音像是刚毕业的,说话有朝气哈哈

面试官:没有,很老,96年的,其实都还好,学习的时候你在学校可能得不到实践,很多东西都需要自己去实践一遍,才能得到证明,叫什么来着,我们学习的时候可能学不到很多,但是我们永远都希望找到一个最优解,比如你去食堂的路,有很多,但最短的只有一条,这就是你工作,学习积累的目的,然后,我觉得你还挺不错的,现在还是大三

最后聊了聊目前的情况,公司的地址,技术栈,出勤等等,后续二面什么的

最后

其实面试挺累的,尤其是对自身要求较高的同学,但是碰到这个面试官,瞬间让我对面试抱有一丝期待,如果面试官都这样去和我面试,那将会非常快乐,收获很多,很多时候碰到的面试官都是语气懒散,甚至还有的带气泡音……不像这个面试官,还能够耐心教你,真的很幸运,也希望他能找到合适的人选

如果你对春招感兴趣,可以加我的个人微信:Dolphin_Fung,我和我的小伙伴们有个面试群,可以进群讨论你面试过程中遇到的问题,我们一起解决

另外有不懂之处欢迎在评论区留言,如果觉得文章对你学习有所帮助,还请”点赞+评论+收藏“一键三连,感谢支持!