22年1月10号,去了一家公司面试。
这家公司距离我现在所在大约10分钟车程,公司在一个公寓办公楼的39层,讲道理这个高度我还是有点眩晕的。
因为是中午抽空面试,所以来的比较早,然后做了一套面试题,实在是很简单,我怀疑就是上网搜的。
面试的时候前端面试的人员不在,后来等到快一点半的时候才正式进入面试过程,在此之前和人事聊了聊。
这个公司整体规模是上下两层,不过感觉面积不大,做的电商教育培训,没有年终奖,然后月薪资浮动。从来没有遇到过这种计价方式。没有传统意义上的那种公司氛围,都是开放办公,几个人在一个屋,说实话还是可以的(对比现在),不过也有不太好的地方,太拥挤了,而且开着空调,通风不是很好(估计一人感冒会波及所有人。技术人员也不不多,大概也就3后+2前+2app+1产品+1UI的配置。
先来说说面试题。
总共问了几个,大部分我都觉得问的很莫名其妙,题目应该也是LeetCode抄来的。
- 根据给定的number类型数组和排位数字,找到数组中第N大的数字,相同数值排名相同。
我是这么考虑的,首先,将数组去重,然后倒序排序,然后再用下标值取值就行。
const rankArr = [1,2,5,3,8,5,4,7,1,9];
function rank(arr,level){
const rankArray = Array.from(new Set(arr)).sort((a,b)=>b-a);
const rankLevel = level<1?1: (level>rankArray.length?rankArray.length:level)
return rankArray[rankLevel-1]
}
// check
rank(rankArr,1) // top rank is 9
rank(rankArr,10) // floor rank is 1
验证通过。不过我觉得他好像没有明白我的设计想法,不是很满意,我也不知道问题在哪儿
虽然可以通过其他方式解决,比如:首先第一步就是要倒叙排序,然后再通过依次取值判断当前的值的索引值
function rank(arr,level){
let rankNum = NaN;
let levelIndex = 0;
arr.sort((a,b)=>b-a).some((num)=>{
if(isNaN(rankNum) || levelIndex<level){
if(rankNum != num ){
levelIndex+=1;
}
rankNum = num;
return false;
}
return true;
})
return rankNum;
}
不过这种方式还是觉得复杂了点。所以作为个人还是喜欢上面的方式,也许有更好的,只是我想不到了。
第二个问题比较奇葩,我觉得一般人都不会太能想到这个吧,也没有实际使用过。
- 使用一种方式,让一段文字显示完整的下划线,即使折行,依旧让下划线填充整行?
讲道理,这个题目我是真不会,css里text-decoration也不具备这个能力,甚至我都没有遇见过这种需求。后来上网求助了一番,只找到了用background-image的repeat-linear-gradient 绘制重复行的形式绘制下划线,这样的确可以按高度呈现,但是需要设置计算字体所占行高,以达到和文字齐平的效果。但是直接以css形式设置的方式或者其他可用的形式的,欢迎留下评论以供参考。
第三个问题是vue相关的。
简述一下vue内组件传值方式
答:prop、emit、inject/provide、event-bus,而vuex被我排除在外。
但是对他而言应该是想知道vuex有没有用过,所以还特地提醒了我一下,但是我回答说,觉得vue并不依赖vuex,所以不属于内部传值方法。
追问我如何实现eventbus,我说这就是一般的事件订阅。继续追问让我实现一个事件监听,并且还追问如何实现一次性绑定,如何取消事件。
class MyEvent {
callback = undefined
isOnce = undefined
constructor(callback, isOnce = false) {
this.callback = callback;
this.isOnce = isOnce
}
}
class MyEventListener {
events = new Map();
on(name, callback, once = false) {
let linstenerStack = this.events.get(name) ?? [];
if (linstenerStack.findIndex((e) => e.callback === callback) === -1) {
linstenerStack.push(new MyEvent(callback, once))
}
this.events.set(name, linstenerStack)
}
once(name, callback) {
this.on(name, callback, true)
}
off(name, callback) {
if (callback) {
let linstenerStack = this.events.get(name)
if (linstenerStack) {
let callIndex = linstenerStack.findIndex((e) => e.callback === callback)
linstenerStack.splice(callIndex, 1)
}
} else {
this.events.delete(name)
}
}
emit(name, value) {
let linstenerStack = this.events.get(name) ?? []
let once = [];
linstenerStack.forEach((e, index) => {
e.callback(value)
if (e.isOnce) {
once.push(index)
}
})
once.forEach((index) => {
linstenerStack.splice(index, 1)
})
}
}
不过当时只是口述了一通,我估计对方没听懂。
下一个问题,打开了京东的界面,说如何知道这个页面下有多少种标签。
这个题我属实有点懵,后来想了想,说可以用 document.documentElement.outerHTML然后通过正则匹配的模式,将所有的标签取出来,然后又忘了怎么写标签取值,只记得非贪心匹配 ?,之前写网络爬虫时候,文本解析的有点吐,所以这次绕到这个弯子里去了。实际上可以用
Array.from(new Set([].map.call(document.querySelectorAll("*"),(node)=>node.nodeName)))
不过我说很少用到通配符,css里也不建议使用。他问我说为什么,我说是效率问题。他说你知道这个速度是多少吗?是多少多少云云。
最后一个问题,什么是event loop
答:是微任务、宏任务吗。他说算是吧。我说,宏任务包括I/O和setTimeout setInterval等等,然后微任务包括 Promise.then、MutationObserver、process.nextTick 之类的,微任务会在宏任务执行栈之间执行。
追问,你知道浏览器的4ms延时吗?答:我是依稀记得有这件事,setTimeout设置时,如果是0ms,就会被设置为4ms。追问,你知道为什么要这么设置吗?心里猜肯定是浏览器的效率问题。但是具体为什么,我也不清楚。
回来百度一顿,才知道是当年chrome是支持0ms设置的,但是偶然某个大公司的项目(雅虎?)发现会出现cpu spinning导致发热和能耗损失,其他问题,后来修改为5层setTimeout叠加的情况下,第五层之后会被设置为4ms。
这个问题算是一个课外小知识了吧。
虽然面试没通过,不过我也发现了一些问题,我的表述和对方想听到的内容总是会产生冲突,而导致面试人对我个人的怀疑,纵然有很多知道的内容,但是企业也不一定需要你,(面试官的能力决定了企业的能力)。其二,是个人面试过程中的表述,总体上需要明白面试官的问题和背后的问题。
以上,我觉得多背点面试题,反而成功率会高,但是不是我的性格。