写在前面
时间轴:
笔试==>一面3.25(基础面 52min)==>二面3.26(压力面 2.5h)==>三面4.1(主管面 31min)电话形式
已经拿到头条和美团的offer了,百度的流程太慢了,不想等了。整理一下面经,回馈牛客。
另外美团跟字节跳动的面筋已经整理好了,欢迎大家来捧场
美团点评 前端12+HR+补面(已拿offer)
字节跳动-教育业务 前端三轮面试总结(已拿offer)
百度云 3.25 (一面 52min)
这个一面来的非常突然,下午4点钟打电话约的5点面试,也就是只有1个小时准备时间,吓得我赶紧在牛客快速浏览了一下以往的面经。不过面试起来就轻松了许多
- 自我介绍以及项目经历(姓名、学校、前端相关经历)
- 讲一下刚说的小米做的重构吧,之前用的什么技术栈?转到React原因,有什么优势(phtml模板升级到React,解决历史遗留问题、方便后续开发维护,架构升级,页面结构重构,SSR解决SAP的SEO问题巴拉巴拉)
问一下前端基础知识
- CSS盒模型能说一下吗(margin+border+padding+content;border-box,content-box)
- position有哪些值,怎么定位的(static、relative、absolute、fixed、sticky;分别是静态文档流、相对文档流位置偏移,根据第一个非static的父节点定位,根据viewport定位,static+fixed的组合;absolute与fixed脱离文档流)
- 垂直水平居中的几种方式:(flex布局、绝对定位+负margin、绝对定位+transform)
- 说到transform:translate -50%,这个是相对谁计算的(元素本身)
- left和top的 50%呢?(外面那个用来定位的盒子)
- 说一下浏览器的事件循环吧(执行栈、宏任务队列、微任务队列;执行一个宏任务之后清空一次微任务再执行下一个宏任务)
- 打个岔,有一个小问题,虽然感觉你是在自己讲,但是为啥你眼睛总在往上看(你没开摄像头,我觉得看哪都OK,就习惯性向上了【不推荐大家这么做】)
- 是不是上面放了个显示器:smile:但是从流畅度来说又不像,想排除一下这个可能。(我直接把上面给她看了,除了墙啥也没有)
- 你后面还是往下看吧,我们继续
- 浏览器的缓存策略、强缓存与协商缓存的区别(浏览器请求资源前会先看有没有缓存,有且没有过期就返回200,直接使用缓存,这就是强缓存,用到expire或者max-age;如果有缓存但是过期了,就发起请求,带上
Etag
或者Last-Modified
,然后服务器响应头带上If-Not-Matched
或者If-Modified-Since
,如果没有更新就返回304状态码,否则返回200并发送新的资源) - 简历上有提到webpack,简单讲一下loader和plugin的区别吧(loader是加载器,将js不支持的格式或者资源转换成支持的格式,plugin自己去设计功能函数,在暴露出来的生命周期钩子中调用,相当于是对webpack的功能的增强)
- 对同一个文件类型定义了多个loader,比如顺序是A、B、C,实际执行的顺序是怎么样的(不清楚)(官网解释从右向左执行,即C->B->A)
- 能说一下Vue中v-if与v-show的区别吗?(v-if为false是没有DOM,v-show为false是display:none;v-if切换状态对性能的影响更大,因为涉及到DOM插入删除)
- Vue里面数据绑定的原理(双向绑定=数据劫持+发布订阅模式;vue2.0用Object.defineProperty遍历对象的所有属性,劫持getter与setter,vue3改成使用Proxy对象完成劫持整个对象,2.0对数组不友好,性能消耗更大。发布订阅实现一个EventEmiter,一个对象,属性名就是事件名,值是回调函数的数组,注册时间就是push回调函数,emit就是找到对应的数组遍历执行一遍)
- 你说的数组的push无法通过defineProperty完成监听,可以通过什么方式去实现呢?(源码里是通过修改对象里数组的原型上的方法用了自己定义的方法进行覆盖,劫持原型链方法)
- Git有用过嘛?(在小米实习用了很多)
- 说一下Git常用的命令(init、clone、add、commit、push、pull、fetch、merge、checkout、branch、reset、revert、cherry-pick、status)
- 多人协同开发是怎么进行的?(本地:Relese、test、开发分支;远端Relese、test、开发分支;接到新的需求,同步本地的Relese然后迁出一条开发分支,本地开发,开发通过之后合并到本地test,再推送到远端的test,在测试环境发布、等待运营和产品检查,通过后发起上线,将本地开发分支push到远端然后发起MR,code review通过之后,合并代码,等待运营发布)
- 如果远程test测试没问题,怎么保证本地的开发分支没问题。也有可能其他人修改掉了你的问题啊(一个人修改一个问题,如果有冲突,去找上一个修改者,确定使用哪一种方案,然后将改的代码合并在发布)
做几道编程题吧(面试官提醒:不要切出页面,后台看得到)
输入一个数组,输出一个数组,每个元素取平方(太简单了,就是map的应用嘛,随手一行代码搞定)
const arr = [1, 2, 3, 4] //输出 [1, 4, 9, 16] let res = arr.map(v=>v*v) console.log(res)
- 为啥res用let不用const,讲一下let、var、const的区别吧(let和const都是ES6的语法,属于块级作用域;var属于函数级作用域,const声明常量,let声明变量,const声明的常量对象只有第一层不可修改;用let只是个人习惯,后面可能会对结果进一步处理)
对象数组转为对象,考察reduce的使用
// 输入 const arr = [{name:"zhao",age:20},{name:"qian", age:30}]; // 用reduce 进行数据转换 输出: // { zhao: { name: ‘zhao’, age: 20 }, qian: { name: ‘qian’, age: 30 } } const arr = [{name:"zhao",age:20}, {name:"qian", age:30}]; const res = arr.reduce((acc,cur)=>{ acc[cur.name] = cur; return acc; }, {}) // 面试官非要看运行结果就遍历了一下对象 Object.keys(res).forEach(key=>{ console.log(key,res[key]) })
数据 扁平化、去重、排序(随手写了一个,这里有许多种实现)
const arr=[1, [3, [2, 3, [6, 5]]]]; var res = Array.from(new Set(flat(arr))).sort((a,b)=>a-b) console.log(res) // 最开始是用arr.flatten()扁平化,报错就知道单词拼错了,顺手就自己实现了一个。后面发现是flat()囧 function flat(arr){ return arr.toString().split(',').map(v=>+v) }
- 你知道是有个方法可以直接扁平化的吧(是的,但是可能拼错函数名了)
- 如果不借用字符串,怎么使用原生的数组api完成(准备开始写代码)
- 你说一下思路就好(reduce遍历数组,如果不是数组就用concat拼接,如果是数组就递归调用)参考实现
// 使用 reduce、concat 和递归展开无限多层嵌套的数组 var arr1 = [1,2,3,[1,2,3,4, [2,3,4]]]; function flatDeep(arr, d = 1) { return d > 0 ? arr.reduce((acc, val) => acc.concat(Array.isArray(val) ? flatDeep(val, d - 1) : val), []) : arr.slice(); }; flatDeep(arr1, Infinity); // [1, 2, 3, 1, 2, 3, 4, 2, 3, 4]
是不是之前准备过这种题目(面试官的声音有点颤抖)(这种题目很常见嘛,之前面试的时候遇到,然后就有练习过类似的手写api,例如函数柯里化、节流、防抖、去重、扁平化,reduce实现map……都写过)
你是17年开始学习前端的吗?(说了一下自己跟前端的相关的经历,大致就是:大一参加Wesharp了解到前端,自我学习,大二参加奇舞团培训营,大三跟着学院的课学后端,然后说了一下对前端跟后端的看法,为什么选择前端,大三暑假在小米实习)
我这边没啥问题,你有什么问题吗?
- 想了解团队做的业务,用的技术栈(有官网配置的cms系统用React;产品的控制台用的百度自己的框架san;百度云APP用的Vue,数据平台用的angular,还有一些其他的业务)
- 想了解一下你对常见的三种框架React、Vue和Angular的看法,angular好像不怎么火了(angular不受欢迎可能是因为太重了,不灵活,vue跟react上手更简单,更轻量,react比vue更重一些,框架选型除了适不适合之外还有一些历史遗留问题,并不一定都是最适合或者流行的框架 。React用的人最多)
- 面试结果大概需要多久呢?(需要去跟同事沟通,面试通过的话,预计这两天就约你)
- 之后会不会跟今天一样一个电话打过来然后一个小时之后就面试,吓死我了(面试官表示需要看他们时间,她今天实在是太忙了,你今天表现也挺好的嘛:smile:,对你没有任何影响,一般会提前约好,之后不会这么急)
这个一面跟之前面的美团以及字节相比还是蛮简单的,面试氛围也很轻松,到最后看面试官的态度肯定是过了。今天就先写到这吧,明天再更新二面的内容,跟一面完全不是一个level的(可能觉得需要给我一点震慑)。
百度云 3.26 (二面 1h50min)
取2个数组的交集并且不去重
case 1: const arr0 = [1, 3, 2, 4] const arr0 = [3, 5, 2, 2, 10] // result [3, 2]
case2:
const arr0 = [1, 3, 2, 2, 4]
const arr0 = [3, 5, 2, 2, 10]
// result
[3, 2, 2]
```javascript function(arr1,arr2){ return arr1.filter(v=>arr2.includes(v)) }
如果
arr1
有三个2,结果还是[3,2]吗?(换一种思路,用对象收集元素出现次数,同时存在时取较小的数字)function func (arr1,arr2){ // return arr1.filter(v=>arr2.includes(v)) let obj1 = helper(arr1); let obj2 = helper(arr2); let res = '' Object.keys(obj1).forEach( (key)=>{ if(obj2[key] !==undefined){ let min = Math.min(obj1[key],obj2[key]) res+=key.repeat(min) } } ) return res.split('') } function helper(arr){ return arr.reduce((acc,cur)=>{ if(acc[cur] !== undefined)acc[cur] += 1 else acc[cur] = 1 return acc },{}) } const res = func(arr0,arr1) console.log(res)
这个的时间复杂度是多少?(不考虑repeat的复杂度应该是O(n))
仔细想想需要用两个对象吗?(只需要一个对象就好)
function func2(arr1,arr2){ let obj1 = helper(arr1); return arr2.filter(key=>{ if(obj1[key]>0){ obj1[key]-=1; return true } return false }) } const res2 = func2(arr0,arr1) console.log(res2)
三版代码加沟通一共用了27 min
百度云的一页介绍;目录树上一篇、下一篇功能实现,即给定一棵树中某一个节点,算出它相邻节点(父节点不一定相同),如果找不到同级,往上找父级,可以一步一步做。(不考虑空节点就是树的层序遍历嘛)
function TreeNode(val){ this.val = val; this.children = [] } const obj ={ val:1, children:[ { val:2, children:[{val:5},{val:6}] }, { val:3, children:[{val:7},{val:8}] }, { val:4, children:[{val:9},{val:10}] }, ] } function func(root){ let queue = [root]; let res = []; while(queue.length){ let node = queue.shift(); // 这里最开始把unshift记成队头弹出,爆栈了,向面试官申请用vscode调试一步一步测才发现,-_-|| res.push(node.val); if(node.children !== undefined){ node.children.forEach(v=>queue.push(v)) } } return res } const res = func(obj) console.log(res)
写BUG、调BUG一共用了28min
实现一个类
jQuery
的DOM操作类,功能包括获取元素、获取与设置html
文本、获取与设置css
样式、链式调用// 实现一个dom类,能够对做这些操作 // 获取元素 const el = dom('#id'); // 获取元素下的html文本 const html = el.html(); // 获取css样式 const style = el.css('background'); // 设置css样式 el.setCss({background: 'red'}); // 设置元素下的html文本 el.setHtml(''); // 最好能链式调用 dom('#id').setHtml().setCss({background: 'red'});
// 以下代码未经过测试,思路就是获取DOM节点,封装对应的DOM操作,链式调用返回this。 // 如果代码有问题,欢迎在评论区指出或补充 class DOM { constructor(selector) { this.nodes = document.querySelectorAll(selector); } html() { let html = []; this.nodes.forEach(node => { temp.push(node.innerHTML); }); return html; } css(attr) { let attrs = []; this.nodes.forEach(node => { temp.push(node.style[attr]); }); return attrs; } setCss(obj) { this.nodes.forEach(node => { Object.keys(obj).forEach(attr => { node.style[attr] = obj[attr]; }); }); return this; } setHtml(htmlText) { this.nodes.forEach(node => { node.innerHTML = htmlText; }); return this; } } function dom(selector) { return new DOM(selector); }
你知道前端路由怎么实现吗(SPA,hashchange,location.replace, history.go)
- 大概实现一下
const route = new Router() route.goto('url') route.goback()
// 当时写的比较乱,这个是后面自己整理的 const app = document.querySelector('#app'); class Router { constructor(routerList) { this.list = routerList; this.el = app; window.addEventListener('hashchange', e => this.handler()); } render(state) { let ele = this.list.find(ele => ele.path === state); ele = ele ? ele : this.list.find(ele => ele.path === "*"); this.el.innerHTML = ele.component; } handler() { this.render(this.getState()); } getState() { const hash = window.location.hash; return hash ? hash.slice(1) : '/'; } goto(url) { window.location.replace(url); } goback(n) { window.history.go(-1); } }
- 你觉得在小米实习影响最深刻的事情(js滚轮动画,讲了一下具体实现,监听滚轮,滚轮盒子与动画盒子,动画进度控制)
- 用的第三方库(jQueryDOM操作)
- 是移动端吗?(是PC,移动化屏幕太小不适合复杂动画)
- 做的都是展示类,动效类的,有没有一些比较复杂的数据校验、字段联动(没机会)
- 页面性能优化(资源加载优化、动画重绘回流优化、SEO优化)
- 浏览器由哪些部分组成(JS引擎、渲染引擎、网络通信模块、定时器模块、文件IO)
- 渲染过程(解析DOM+解析CSSOM+执行JS==>组装渲染树==>计算布局==>绘制==》页面显示)
- 团队大小(前端20人左右,业务3~4)
- 团队协作、跟人沟通、遇到让你很不爽或者很好的沟通对象(举了两个例子,怎么解决问题)
- 为什么想做前端呢?(个人选择、反馈感更好、成就感更强)
- 觉得自己有哪些不足的地方(实践经验比较少、框架使用比较少)
- 有什么要问吗?
- 之前了解到团队是做百度云,感觉阿里云、腾讯云市场影响力比百度云更强,想了解这是为什么(云服务器入场比较晚、面向对象都是政府和私有部署,面向学生的比较少)
- 之前那个前端路由的实现思路能讲一下吗?(没你写的那么复杂、接收路由列表地址与对应组件、注册handle函数、调用api封装一下)
二面基本上就是全写代码,然后加上一些团队合作上面的考核,跟一面相比不是一个level,也发现自己的不足之处,后面有待加强。
3月30日三面面试官打电话约三面,随便问了一下手上的offer(头条拿offer、美团面到HR)、offer位置在哪?以后想在哪里发展,字节的offer薪资给到多少,4月1日晚上9点电话面试
主管面,
电话里就聊了一下手上的offer、百度的薪资情况、然后再就是前端相关的经历、为什么学前端这种问题,然后具体问了实习项目的事情。
具体内容不想写啦,反正最后也没去,这么写不会被打吧
全部评论
(5) 回帖