专栏名称: SegmentFault思否
SegmentFault (www.sf.gg)开发者社区,是中国年轻开发者喜爱的极客社区,我们为开发者提供最纯粹的技术交流和分享平台。
目录
相关文章推荐
OSC开源社区  ·  RAG市场的2024:随需而变,从狂热到理性 ·  21 小时前  
程序员的那些事  ·  OpenAI ... ·  昨天  
OSC开源社区  ·  升级到Svelte ... ·  4 天前  
程序猿  ·  “我真的受够了Ubuntu!” ·  3 天前  
程序员小灰  ·  DeepSeek做AI代写,彻底爆了! ·  5 天前  
51好读  ›  专栏  ›  SegmentFault思否

百度、有赞、阿里前端面试总结

SegmentFault思否  · 公众号  · 程序员  · 2018-11-21 08:00

正文

前言

人家都说,前端需要每年定期出来面面试,衡量一下自己当前的技术水平以及价值,本人17年7月份,毕业到现在都没出来试过,也没很想换工作,就出来试试,看看自己水平咋样。

以下为我现场面试时候的一些回答,部分因人而异的问题我就不回答了,回答的都为参考答案,也有部分错误的地方或者不好的地方,有更好的答案的可以在评论区评论。

百度 WEB前端工程师 连续五面 全程3约个小时

一面

先完成笔试题:

1、实现一个函数,判断输入是不是回文字符串。

  1. function run(input) {

  2.  if (typeof input !== 'string') return false;

  3.  return input.split('').reverse().join('') === input;

  4. }

2、两种以上方式实现已知或者未知宽度的垂直水平居中。

  1. // 1

  2. .wraper {

  3.  position: relative;

  4.  .box {

  5.    position: absolute;

  6.    top: 50 %;

  7.    left: 50%;

  8.    width: 100px;

  9.    height: 100px;

  10.    margin: -50px 0 0 -50px;

  11.  }

  12. }

  13. // 2

  14. .wraper {

  15.  position: relative;

  16.  .box {

  17.    position: absolute;

  18.    top: 50%;

  19.    left: 50%;

  20.    transform: translate(- 50%, -50%);

  21.  }

  22. }

  23. // 3

  24. .wraper {

  25.  .box {

  26.    display: flex;

  27.    justify-content:center;

  28.    align-items: center;

  29.    height: 100px;

  30.  }

  31. }

  32. // 4

  33. .wraper {

  34.  display: table;

  35.  .box {

  36.    display : table-cell;

  37.    vertical-align: middle;

  38.  }

  39. }

3、实现效果,点击容器内的图标,图标边框变成border 1px solid red,点击空白处重置。

  1. const box = document.getElementById('box');

  2. function isIcon(target) {

  3.  return target.className.includes('icon');

  4. }

  5. box.onClick = function(e) {

  6.  e.stopPropagation();

  7.  const target = e.target;

  8.   if (isIcon(target)) {

  9.    target.style.border = '1px solid red';

  10.  }

  11. }

  12. const doc = document;

  13. doc.onclick = function(e) {

  14.  const children = box.children;

  15.  for(let i; i < children.length; i++) {

  16.    if (isIcon(children[i])) {

  17.      children[i].style.border = 'none';

  18.     }

  19.  }

  20. }

4、请简单实现双向数据绑定mvvm。

  1. id="input"/>

  1. const data = {};

  2. const input = document.getElementById('input');

  3. Object.defineProperty(data, 'text', {

  4.    set(value) {

  5.    input.value = value;

  6.    this.value = value;

  7.  }

  8. });

  9. input.onChange = function(e) {

  10.  data.text = e.target.value;

  11. }

5、实现Storage,使得该对象为单例,并对localStorage进行封装设置值setItem(key,value)和getItem(key)

  1. var instance = null;

  2. class Storage {

  3.  static getInstance() {

  4.    if (!instance) {

  5.      instance = new Storage();

  6.    }

  7.    return instance;

  8.  }

  9.  setItem = (key, value) => localStorage.setItem(key , value),

  10.  getItem = key => localStorage.getItem(key)

  11. }

Q1 你的技术栈主要是react,那你说说你用react有什么坑点?

1、JSX做表达式判断时候,需要强转为boolean类型,如:

  1. render() {

  2.  const b = 0;

  3.  return <div>

  4.    {

  5.      !!b && <div>这是一段文本div>

  6.    }

  7.  div>

  8. }

如果不使用 !!b 进行强转数据类型,会在页面里面输出 0。

2、尽量不要在 componentWillReviceProps 里使用 setState,如果一定要使用,那么需要判断结束条件,不然会出现无限重渲染,导致页面崩溃。

3、给组件添加ref时候,尽量不要使用匿名函数,因为当组件更新的时候,匿名函数会被当做新的prop处理,让ref属性接受到新函数的时候,react内部会先清空ref,也就是会以null为回调参数先执行一次ref这个props,然后在以该组件的实例执行一次ref,所以用匿名函数做ref的时候,有的时候去ref赋值后的属性会取到null。详情见

4、遍历子节点的时候,不要用 index 作为组件的 key 进行传入。

Q2 我现在有一个button,要用react在上面绑定点击事件,要怎么做?

  1. class Demo {

  2.  render () {

  3.    return <button onClick={(e) => {

  4.      alert('我点击了按钮')

  5.    }}>

  6.      按钮

  7.    button>

  8.  }

  9. }

Q3 接上一个问题,你觉得你这样设置点击事件会有什么问题吗?

由于onClick使用的是匿名函数,所有每次重渲染的时候,会把该onClick当做一个新的prop来处理,会将内部缓存的onClick事件进行重新赋值,所以相对直接使用函数来说,可能有一点的性能下降(个人认为)。

修改:

  1. class Demo {

  2.  onClick = (e) => {

  3.    alert('我点击了按钮')

  4.  }

  5.  render() {

  6.     return <button onClick={this.onClick}>

  7.      按钮

  8.    button>

  9.  }

  10. }

当然你在内部声明的不是箭头函数,然后你可能需要在设置onClick的时候使用bind绑定上下文,这样的效果和先前的使用匿名函数差不多,因为bind会返回新的函数,也会被react认为是一个新的prop。

Q4 你说说event loop吧

首先,js是单线程的,主要的任务是处理用户的交互,而用户的交互无非就是响应DOM的增删改,使用事件队列的形式,一次事件循环只处理一个事件响应,使得脚本执行相对连续,所以有了事件队列,用来储存待执行的事件,那么事件队列的事件从哪里被push进来的呢。那就是另外一个线程叫事件触发线程做的事情了,他的作用主要是在定时触发器线程、异步HTTP请求线程满足特定条件下的回调函数push到事件队列中,等待js引擎空闲的时候去执行,当然js引擎执行过程中有优先级之分,首先js引擎在一次事件循环中,会先执行js线程的主任务,然后会去查找是否有微任务microtask(promise),如果有那就优先执行微任务,如果没有,在去查找宏任务macrotask(setTimeout、setInterval)进行执行。

Q5 说说事件流吧

事件流分为两种,捕获事件流和冒泡事件流。

  • 捕获事件流从根节点开始执行,一直往子节点查找执行,直到查找执行到目标节点。

  • 冒泡事件流从目标节点开始执行,一直往父节点冒泡查找执行,直到查到到根节点。

事件流分为三个阶段,一个是捕获节点,一个是处于目标节点阶段,一个是冒泡阶段。

Q6 我现在有一个进度条,进度条中间有一串文字,当我的进度条覆盖了文字之后,文字要与进度条反色,怎么实现?

。。。当时我给的是js的方案,在进度条宽度变化的时候,计算盖过每一个文字的50%,如果超过,设置文字相反颜色。

当然css也有对应的方案,也就是 mix-blend-mode,我并没有接触过。

对应html也有对应方案,也就设置两个相同位置但是颜色相反的dom结构在重叠在一起,顶层覆盖底层,最顶层的进度条取overflow为hidden,其宽度就为进度。

二面

Q1 你为什么要离开上一家公司?

-

Q2 你觉得理想的前端地位是什么?

-

Q3 那你意识到问题所在,你又尝试过解决问题吗?

-

三面

Q1 说一下你上一家公司的一个整体开发流程吧

-

Q2 react 的虚拟dom是怎么实现的

首先说说为什么要使用Virturl DOM,因为操作真实DOM的耗费的性能代价太高,所以react内部使用js实现了一套dom结构,在每次操作在和真实dom之前,使用实现好的diff算法,对虚拟dom进行比较,递归找出有变化的dom节点,然后对其进行更新操作。为了实现虚拟DOM,我们需要把每一种节点类型抽象成对象,每一种节点类型有自己的属性,也就是prop,每次进行diff的时候,react会先比较该节点类型,假如节点类型不一样,那么react会直接删除该节点,然后直接创建新的节点插入到其中,假如节点类型一样,那么会比较prop是否有更新,假如有prop不一样,那么react会判定该节点有更新,那么重渲染该节点,然后在对其子节点进行比较,一层一层往下,直到没有子节点。

Q3 react 的渲染过程中,兄弟节点之间是怎么处理的?也就是key值不一样的时候。

通常我们输出节点的时候都是map一个数组然后返回一个ReactNode,为了方便react内部进行优化,我们必须给每一个reactNode添加key,这个key prop在设计值处不是给开发者用的,而是给react用的,大概的作用就是给每一个reactNode添加一个身份标识,方便react进行识别,在重渲染过程中,如果key一样,若组件属性有所变化,则react只更新组件对应的属性;没有变化则不更新,如果key不一样,则react先销毁该组件,然后重新创建该组件。

Q4 我现在有一个数组[1,2,3,4],请实现算法,得到这个数组的全排列的数组,如[2,1,3,4],[2,1,4,3]。。。。你这个算法的时间复杂度是多少

这个我没写出来,大概给了个思路,将每一个数组拆除俩个小数组进行求它的全排列,然后得到的结果互相之间又进行全排列,然后把最后的结果连接起来。。。

感兴趣的同学见数组全排列

Q5 我现在有一个背包,容量为m,然后有n个货物,重量分别为w1,w2,w3...wn,每个货物的价值是v1,v2,v3...vn,w和v没有任何关系,请求背包能装下的最大价值。

这个我也没写出来,也给了个思路,首先使用Q4的方法得到货物重量数组的全组合(包括拆分成小数组的全组合),然后计算每一个组合的价值,并进行排序,然后遍历数组,找到价值较高切刚好能装进背包m的组合。

本题 动态规划面试题 ,感兴趣的同学请自行百度或者谷歌。

四面

Q1 请说一下你的上一家公司的研发发布流程。

-

Q2 你说一下webpack的一些plugin,怎么使用webpack对项目进行优化。

正好最近在做webpack构建优化和性能优化的事儿,当时吹了大概15~20分钟吧,插件请见webpack插件归纳总结。

构建优化:

  1. 减少编译体积 ContextReplacementPugin、IgnorePlugin、babel-plugin-import、babel-plugin-transform-runtime

  2. 并行编译 happypack、thread-loader、uglifyjsWebpackPlugin开启并行

  3. 缓存 cache-loader、hard-source-webpack-plugin、uglifyjsWebpackPlugin开启缓存、babel-loader开启缓存

  4. 预编译 dllWebpackPlugin && DllReferencePlugin、auto-dll-webapck-plugin

性能优化:

  1. 减少编译体积 Tree-shaking、Scope Hositing

  2. hash缓存 webpack-md5-plugin

  3. 拆包 splitChunksPlugin、import()、require.ensure

Q3 es6 class 的new实例和es5的new实例有什么区别

这个我觉得是一样的(当时因为很少看babel编译之后的结果),面试官说不一样。。。后来我看了一下babel的编译结果,发现只是类的方法声明的过程不一样而已,最后new的结果是一样的。。。具体答案现在我也不知道。。。

Q4 看你简历上写了canvas,你说一下为什么canvas的图片为什么过有跨域问题

canvas图片为什么跨域我不知道,至今没查出来,也差不多,大概跨域原因和浏览器跨域的原因是一样的吧。

Q5 我现在有一个canvas,上面随机布着一些黑块,请实现方法,计算canvas上有多少个黑块

使用getImageData获取像素数组,然后遍历数组,把在遍历节点的过程中,查看节点上下左右的像素颜色是否相同,如果相同,然后设置标识,最后groupBy一下所有像素。(这是我当时的方案)

其他更好的答案见地址

Q6 请手写实现一个promise

这个就不写了,详情见promise实现原理

注:四面是一个超级可爱的小姐姐,电脑给我让我写完之后,我说我写得差不多了,然后电脑给她,然后她竟然默默的在看我的代码,尝试寻找我的思路,也没有问我实现思路是啥,然后我就问她,你不应该是让我给你解释我的代码思路吗。。。你竟然在尝试寻找我的思路,我自己都不知道我自己是思路是啥。。。然后我两都笑了,哈哈哈。最后结束的时候我说我午饭还没吃,她还叫了另外一个小哥哥先带了下去吃饭,真是一个善良的小姐姐,非常感谢。

五面

Q1 你说一下你的技术有什么特点







请到「今天看啥」查看全文