记一次有趣的面试经历
前两天面了一家公司,面试官小哥哥声音真的很像是刚毕业的大学生,我记得我以前刚学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
盒模型的自身宽度会被border
和padding
挤掉,省略
面试官:你说反了,IE
盒模型没有padding
,border
,你可以说是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
是通过数组的形式,bind
,bind
,有点忘了哈哈
面试官: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个操作,当然简单实现,就只需要用上get
和set
函数,分别作一个依赖收集,和依赖触发,就是像是computed
,watch
,watchEffect
这些依赖,ref
得话,就相当于用上了原生js
的对象的语法,getter
和setter
,分别作依赖收集和依赖出发,不过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
,但是computed
不update
,它直接告诉闭包里面的dirty
,数值脏了,下次用这个值的时候再去判断是否读取这个值
面试官:那我再问你,生命周期啊,一个父组件A,还有一个子组件B,A的created
和mounted
和B的created
和mounted
,这个四个钩子的执行顺序
我:额,既然区分了父子关系,那么一定是父组件的created
先执行,挂载得话应该不一定,应该是接着子组件的created
,最后挂载的话应该是倒着来的,应该是子的挂载先,最后父的挂载
面试官:这道题就不给你答案了,自己有时间下去多研究下,你肯定写过vue
,但是没有刻意去关注这个挂载,渲染顺序对吧
我:挂载肯定在渲染之前嘛
面试官:我说初始化,挂载
我:初始化肯定在挂载之前
面试官:你刚刚讲的东西,我看你答得不肯定嘛,没有尝试过嘛对不对,额……差不多啊,我看看我有没有什么想问的,vue3?……额,泽~,哈哈,掘金上的帖子都是你自己写的吗
我:对!有些可能写的比较久了,你拿来问我可能答得不全
面试官:哈哈,我刚刚问的问题,不就是你自己写的东西吗
我:像是那个生命周期,确实写过,但是没有研究过嵌套的情况
面试官:那你讲讲你的nextTick
的原理吧
我:就是通过那个mutationObserver
打造的,所以是个微任务,其实这个关于微任务有一定的发展史,因为浏览器的兼容问题,里面还有对应的setTimeout
执行,不兼容就会去调用定时器,去模拟这个异步
面试官:其实也不是全是mutationObserver
,有个优先级判断,一层层的判断下去,看你浏览器的支持度,然后你忘记说了一个重要点,就是起到一个渲染完毕的作用
这个时候他在跟我找vue3的源码,然后说了句vue3的源码不好找啊
我:哦!对,差点把这个忘说了,哈哈
面试官:git
也用过吧
我:嗯嗯,git
指令很多,但是平时在学校就用的那几个指令,放到暂存区等等……
面试官:我看你的项目是个小红书,小红书是个瀑布流,那你讲讲这个瀑布流怎么实现的
我:瀑布流可以使用别人写的~
面试官:你引用别人?我要你自己造
我:这应该需要涉及到拿到图片的宽高,然后一系列计算,致使尽可能的填满空间,应该挺复杂的吧
面试官:其实还好哈哈,有时间再跟你讲!好了,我这边没什么问题了,你有什么问题吗
我:你应该挺年轻的吧哈哈哈,感觉你学识很多,听声音像是刚毕业的,说话有朝气哈哈
面试官:没有,很老,96年的,其实都还好,学习的时候你在学校可能得不到实践,很多东西都需要自己去实践一遍,才能得到证明,叫什么来着,我们学习的时候可能学不到很多,但是我们永远都希望找到一个最优解,比如你去食堂的路,有很多,但最短的只有一条,这就是你工作,学习积累的目的,然后,我觉得你还挺不错的,现在还是大三
最后聊了聊目前的情况,公司的地址,技术栈,出勤等等,后续二面什么的
顺便吆喝一句,看新机会的可看看
民族企业核心部门年底前的一波岗,base武汉、深圳、东莞、西安、上海、北京、苏州等地
前、后端or测试>>>直通机会
最后
其实面试挺累的,尤其是对自身要求较高的同学,但是碰到这个面试官,瞬间让我对面试抱有一丝期待,如果面试官都这样去和我面试,那将会非常快乐,收获很多,很多时候碰到的面试官都是语气懒散,甚至还有的带气泡音……不像这个面试官,还能够耐心教你,真的很幸运,也希望他能找到合适的人选
——转载自作者:Dolphin_海豚