参考文章
电话预约
注:电面前,请记得用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] = [];
}
}
}
将输入的数组组装成一颗树状的数据结构,注意边界异常值处理,功能如下所示:
// 输入 1
transform([
{ 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": []
}
]
}
]
}
]
}
*/
// 输入 2
transform([
{ 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": []
}
]
}
]
}
]
}
*/
// 输入 3
transform([
{ 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),
};
}