参考文章
电话预约
注:电面前,请记得用xxx的拨号功能来拨打,会自动隐藏真实号码。避免用自己手机直接拨打。
• 您好,我是xxxx前端技术部的前端工程师:xxx,我这边收到了您的一封简历,现在想和您做一个电话沟通,不知道您现在方便吗?
(如果不方便)
• 好的,那我们再约个时间,你什么时候方便?
面试流程
- 自我介绍
 - 确认对方意向(公司、职位、地点)
 - 应聘者自我介绍
 - 面试相关知识及考察点
 - 面试结束,告知后续的节奏点,比如有人会通知结果
 
面试技术点
HTML
- 行内元素和块级元素有什么区别?各自有哪些代表性的标签?
- 是否独占一行
 - 是否可以互相包含
 
 - 怎么理解 HTML 的语义化?
- html 标签的使用
 - css className 的使用
 - 无障碍
 
 - 纯 html 怎么实现点击表单项的标签文本可以触发右边的单选框勾上?
 - 纯 html 怎么实现点击表单里面的一个按钮触发表单提交?
 
CSS
- css position 有哪些值?默认值是什么?分别是怎么样的行为?
- absolute 相对谁?
 - 答出新的 sticky 加分
 
 - css overflow 有哪些值?默认值是什么?分别是怎样的行为?
 - css box-sizing 有哪些值?默认值是什么?分别是怎样的行为?
 - 水平居中
- 行内元素容器怎么让子元素水平居中?text-align:center;
 - 块级元素容器怎么让子元素水平居中?margin: 0 auto;
 - flex 容器怎么让子元素水平居中? justify-content: center;
 - 如果子元素是绝对定位的,怎么水平居中?left:50%; transform:translate(-50%,0);
 
 - 用 top left 定位和 transform 的区别
- 是否影响父元素大小和兄弟元素位置
 - 性能
 
 - display: none;与visibility: hidden;的区别
 - css 动画一般会有哪些实现?
- transition
 - animation
 - js
 
 - Less
- 怎么定义变量?
 - mixin 的作用是什么?定义的时候加不加括号有什么区别?
 - 父选择器的几种用法?
- 普通
 - 中划线
 
 
 - rem 这个单位了解过吗?
 
JavaScript
- js 中有哪些数据结构类型?
- primitive 的数据类型,可以用 typeof 判断的: undefined、Boolean、Number、String、BigInt、Symbol
 - 复合类型:
- Object:衍生出 Array、Map、Set、WeakMap、WeakSet、Date, typeof 的结果全是 ‘object’
 - Function
 
 
 - 特殊类型:null,typeof 的结果是 ‘object’, 但是本身是 primitive 的
 - 如何判断数据结构类型?
- 最好的方式是 bject.prototype.toString.call,但是自定义的 class 会返回 object,可以用 instanceof 做进一步筛选
 
 - 数组里 forEach 和 map 的使用场景是什么?
- 如果 map 循环里面想要执行异步的逻辑,并且要拿到返回值该怎么办?
 
 - var let const 定义一个变量的差别是啥?
- let 可以在块级作用域
 
 - 一个函数执行时候的 this 取决于什么因素?
- 怎么绑定一个函数执行时候的 this?
- call 和 apply、bind 的作用是什么,有什么区别?
 
 
 - 怎么绑定一个函数执行时候的 this?
 - 箭头函数的准确定义是啥?
 - JS 函数调用是按值传递还是按引用传递?
 - 能说说你对闭包的理解吗?是什么意思?一般有什么应用场景?
 - addEventListener 的第三个参数 capture true false 的差异是啥?
 - 怎么阻止事件冒泡?
 - Promise.all() 和 Promise.race() 的作用分别是啥?
 - 正则表达式后面的 g、i 这些修饰字符分别是什么意思?
 - 怎么获取一个 dom 节点的坐标位置?
 
ES6
- 箭头函数会被 bable 或 ts 编译成啥知道吗?
 - class 会被 bable 或 ts 编译成啥知道吗?
- class 属性,函数
 - constructor 代码和属性初始值代码的顺序
 - class extends 会编译成啥
 - static 属性和 static 方法会编译成啥?
 - constructor 返回值的意义是啥?
 
 - async/await 被 babel 或 ts 往下编译的时候主要思路是啥?
 lodash 的 debounce 和 thottle 分别是干嘛的?
TypeScript
有哪些基础概念?
- interface、type、enum
 
- 泛型的使用场景有哪些?
 - 
React
 react 的 jsx 会被编译成什么样?
- setState 是同步的还是异步的?为什么会设计成这样?
 - class 组件有哪些生命周期?如果是 function 组件,怎么用 hooks 来模拟这些生命周期?
 - react 父组件怎么拿到子组件的变量和方法?
 - react 子组件怎么拿到父组件的变量和方法?
 - react 组件怎么获取到自己渲染的 dom 节点?
 - HOC 高阶组件的原理和应用场景是啥?
 - render props 了解吗?解决什么问题?
 - context 了解吗?解决什么问题?有哪些不同的新老 api?
 - react 的 PureComponent 和 Component 两个基类有啥差异?
 - Portal 了解过吗?作用是啥?
 - react router 的大致原理是啥?
 - virtual dom 存在的意义是什么?
 - react 里面阻止事件冒泡之后,其它地方就一定监听不到了吗?
 - redux 是解决什么问题的?有哪些概念?
 - react-redux 是解决什么问题的?有哪些概念?
 - react 里面 dangerouslySetInnerHtml 是干啥的?
 - mobx 了解吗?主要有哪些概念?
 
antd
- Input 的 value 和 defaultValue 分别是干啥的?
 - Table 组件的 rowKey 是干嘛的?可以设置为随机数吗?可以设置为 1,2,3,4 吗?
 - 如果组件的 state 上有一个变量 dataSource,是给到 antd table 组件的 props,当你想要修改第二行的某一列的字段的时候,该怎么 setState?原因是啥?(immutable)
 - FormItem 的 fildName 熟悉是干嘛的
 - Menu 的 activeKey 和 MenuItem 的 key 有啥关系?在 MenuItem 里面 console.log(this.props.key) 会输出什么?
 - 
Vue
 - 
Node.js
 浏览器端的 js 执行和 node.js 端的 js 执行最大的差异是啥?
- 浏览器端怎么实现密集计算不阻塞页面渲染?
 
- nodejs 的模块系统跟前端的模块系统分别是啥?
 - 了解过 express/koa/egg 吗?
 
网络
- 跨域问题是指什么?
- 浏览器的安全策略,对除了静态资源之外的 xhr 请求有同源限制
 
 - 跨域问题一般有哪些解决方案?原理是啥?
- jsonp:客户端用 script 标签伪装成静态资源请求,避开 xhr 的同源限制,服务端返回一段JavaScript 代码,其中会执行一个客户端 js 作用域内存在的 callback 函数,函数名是客户端指定的,从而拿到返回值
 - cors:客户端发起 fetch 请求的时候指定 cors 模式,服务端返回对应的 cors 头
 
 - cookie 和 session 的主要区别是什么?
 - 主流网站的登录是怎么实现的?
 - HEAD 请求是干嘛的?
 - OPTION 请求是干嘛的?
 - cookie 的 httponly 属性是干嘛的?
 - cookie 的 secure 属性是干嘛的?
 
数据库
- join
 - left join 原理是什么?
 - join 的 on 和 select 的 where 差别是什么?
 - limit 5 和 limit 5, 10 分别是什么意思?
 - 一般应该对哪些字段加索引?
 - 
工程
 webpack
- 解决什么问题的?用过哪些插件?
 - 怎么优化构建速度和减少构建体积?
 - CommonChunkPlugin 了解吗
 
- babel
- 解决什么问题的?用过哪些插件?
 
 - 多人合作时如何保证项目整体的代码质量?
- lint
 - cr
 - test/ci
- jest
 - snapshot
 
 
 - git
- 常用命令有哪些?分别作用是啥?
 - rebase 和 merge 有什么差异?分别在什么场景下用?
 
 - 说说你了解的有哪些景点的设计模式?以及他们分别可以对代码组织起到什么作用?
 
算法
js 里面如果你要实现一个链表,一般会采取怎样的数据结构?大致思路是怎样的?
综合技巧
如果一个网页访问有性能问题,你会怎么办?
- chrome performance 火焰图
 - js 加载体积很大怎么办?
- webpack dynamic import
 
 - 执行卡顿
 
- 如果用户反馈访问你们公司的一个网页看到一个 404 界面,你会怎么办?
- 确认是后端 404 还是前端路由 404,前端路由展开到路由系统
 
 
个人的发展潜力
说说你平常关注的一些技术相关的网站,个人等信息来源?
你觉得写 js 和你平常写 c++ java 有没有什么感受上的差异吗?可以随便谈谈感受
面试结束语
- 我的问题问完了,请问你有什么问题要问的么?
 - 今天的沟通就到这里,沟通的结果我们会尽快反馈给你。谢谢,再见!
 
笔试题
写一段代码使得点击页面的任意div标签时都能弹出当前时间戳
参考答案:
document.body.addEventListener('click', function(ev){var target = ev.target || ev.srcElement;if(target.tagName.toLowerCase() === ''){alert(new Date().getTime())}});
请实现一个 EventBus 模块,可以实现自定义事件的订阅、触发、移除功能,功能如下所示
const eventBus = new EventBus();function handleSleep1(){console.log('sleep1');}function handleSleep2(){console.log('sleep2');}function handleSleep3(){console.log('sleep3');}// 一堆监听eventBus.on('sleep', handleSleep1);eventBus.on('sleep', handleSleep2);eventBus.on('sleep', handleSleep1);eventBus.on('sleep', handleSleep3);// 取消一个eventBus.off('sleep', handleSleep3);// 触发eventBus.emit('sleep');// 预期正确输出是(重复监听不生效、按监听顺序执行、取消的不生效)// sleep1// sleep2// 全部取消eventBus.off('sleep');// 触发eventBus.emit('sleep');// 预期的正确输出是:没有输出
参考答案:
class EventBus {eventPool = {};on(eventName, handler) {if (!this.eventPool[eventName]) {this.eventPool[eventName] = [];}if (this.eventPool[eventName].includes(handler)) {return;}this.eventPool[eventName].push(handler);}emit(eventName) {const pool = this.eventPool[eventName];if (pool) {pool.forEach(handler => handler());}}off(eventName, handler) {if (!this.eventPool[eventName]) {return;}if (handler) {const targetIndex = this.eventPool[eventName].findIndex(item => item === handler);if (targetIndex !== -1) {this.eventPool[eventName].splice(targetIndex, 1);}} else {this.eventPool[eventName] = [];}}}
将输入的数组组装成一颗树状的数据结构,注意边界异常值处理,功能如下所示:
// 输入 1transform([{ id: 1, name: 'i1' },{ id: 2, name: 'i2', parentId: 1 },{ id: 4, name: 'i4', parentId: 3 },{ id: 3, name: 'i3', parentId: 2 },]);// 输出 1/**{"id": 1,"name": "i1","children": [{"id": 2,"name": "i2","parentId": 1,"children": [{"id": 3,"name": "i3","parentId": 2,"children": [{"id": 4,"name": "i4","parentId": 3,"children": []}]}]}]}*/// 输入 2transform([{ id: 1, name: 'i1' },{ id: 2, name: 'i2', parentId: 1 },{ id: 4, name: 'i4', parentId: 3 },{ id: 3, name: 'i3', parentId: 2 },{ id: 11, name: 'i11', parentId: 'UFO' },]);// 输出 2/**{"id": 1,"name": "i1","children": [{"id": 2,"name": "i2","parentId": 1,"children": [{"id": 3,"name": "i3","parentId": 2,"children": [{"id": 4,"name": "i4","parentId": 3,"children": []}]}]}]}*/// 输入 3transform([{ id: 1, name: 'i1', parentId: 4 },{ id: 2, name: 'i2', parentId: 1 },{ id: 3, name: 'i3', parentId: 2 },{ id: 4, name: 'i4', parentId: 3 },]);// 输出 3/**{"id": 1,"name": "i1","children": [{"id": 2,"name": "i2","parentId": 1,"children": [{"id": 3,"name": "i3","parentId": 2,"children": [{"id": 4,"name": "i4","parentId": 3,"children": []}]}]}]}*/
参考答案:
function findTopParent(list) {return list.filter((item) => !item.parentId);}function findChildren(list, targetItem) {return list.filter((item) => item.parentId === targetItem.id);}function getChildren(list, targetItem) {return findChildren(list, targetItem).map((item) => ({...item,children: getChildren(list, item),}));}function transform(list) {if (Object.prototype.toString.call(list) !== '[object Array]') {return {};}// 找到顶级父结构const top = findTopParent(list);if (top.length !== 1) {return {};}const topItem = top[0];// 找到当前父结构的所有子结点return {...topItem,children: getChildren(list, topItem),};}
