最近因为一些原因想要换份工作,通过猎头帮我投递了几家公司,收到了蚂蚁、字节和拼多多的面试邀约,先来说下面试的结果
- 蚂蚁:收到 offer,定级 P6+
- 字节:收到 offer,定级 2-1
- 拼多多:1 面之后未继续流程
拼多多
先来说说拼多多,本来投的是 C 端,结果鬼使神差简历去到了 A 端(管理后台),一面简单了解之后并不愿意去做 A 端,之后也就没有继续后续的流程了。
一面
合并两个数组
concat、for 循环、扩展运算法、push.apply 这些方法都可以
合并两个对象
Object.assign、扩展运算法、手写深浅拷贝 都可以
interface 和 type 的区别
常规题,网上资料很多了,还是看官网的说明比较好
- An interface can be named in an extends or implements clause, but a type alias for an object type literal cannot.
- An interface can have multiple merged declarations, but a type alias for an object type literal cannot.
flex: 0 1 auto 表示什么意思
flex: 0 1 auto 其实就是弹性盒子的默认值,表示 flex-grow
, flex-shrink
和 flex-basis
的简写,分别表示放大比例、缩小比例、分配多余空间之前占据的主轴空间。
详细的可以看下 第 154 题:弹性盒子中 flex: 0 1 auto 表示什么意思[1]
求字符串数组的最长公共前缀
比如输入: ["flower","flow","flight"],输出: "fl"
解题思路是先获取数组中的最大值及最小值字符串,最小字符串与最大字符串的最长公共前缀也为其他字符串的公共前缀,即为字符串数组的最长公共前缀
var longestCommonPrefix = function(strs) {
if (strs === null || strs.length === 0) return "";
if(strs.length === 1) return strs[0]
let min = 0, max = 0
for(let i = 1; i < strs.length; i++) {
if(strs[min] > strs[i]) min = i
if(strs[max] < strs[i]) max = i
}
for(let j = 0; j < strs[min].length; j++) {
if(strs[min].charAt(j) !== strs[max].charAt(j)) {
return strs[min].substring(0, j)
}
}
return strs[min]
};
当然还有其他解法,可以看下这篇,图解拼多多&leetcode14:最长公共前缀[2]
手写 Koa 的 compose 方法
这里实现一个简化版,如果问你异步如何处理的话,dispatch 函数里面 return promise 就好了
function compose(middleware) {
return function() {
return dispatch(0)
function dispatch(i) {
let fn = middleware[i]
if (!fn) return
return fn(function next() {
return dispatch(i + 1)
})
}
}
}
获取精度更高的时间
- 浏览器使用
performance.now()
可以获取到 performance.timing.navigationStart
到当前时间之间的微秒数 - Node.js 使用
process.hrtime
返回一个数组,其中第一个元素的时间以秒为单位,第二个元素为剩余的纳秒
获取首屏时间
- H5 如果页面首屏有图片
首屏时间 = 首屏图片全部加载完毕的时刻 - performance.timing.navigationStart
- 如果页面首屏没有图片
首屏时间 = performance.timing.domContentLoadedEventStart - performance.timing.navigationStart
- 小程序通过拦截 setData 调用方式计算
git rebase 和 merge 的区别
常规题了,主要的区别在于是否保留分支的 commit 提交节点,rebase 会给你一个简洁的线性历史树
蚂蚁
蚂蚁一共是 4 轮技术面 + 1 轮 HR 面,耗时 10 天,流程相对来说还算快了。4 轮技术面都是电话面,最后的终面(HR 面)是视频面。蚂蚁的面试主要还是根据简历提问,所以简历上写的点都需要好好准备下。
其中比较难的是第 4 面和 HR 面,因为这两面才是最终决定是否录用你以及确定录用之后的职级,4 面的面试官一般是 P8 或者 P9,Level 比较高,会从聊天的过程中考察你,另外 HR 面拥有一票否决权,如果被 HR 否决,前面面的再好也没用,这两面都需要好好准备下。
一面
一面又叫简历评估面,主要对简历上的东西进行提问,一面结束之后会通过邮件发几道编程题,难度比字节大,但是不限定时间,最好当天做完发过去
有没有做过 node 端
介绍了下我的「高级前端面试」小程序和写过的几个 node 脚本,聊了下整体的架构、数据库(mysql + redis)、部署、监控这些方面
大型复杂项目开发协作经验、遇到的问题和解决方案
主要介绍下 git 协作流程
如果让你负责一个新项目,如何选择技术栈,如何避免多端合作可能遇到的问题
脚手架开发、约定团队开发规范、Lint 等;根据团队的技术栈、成员能力等去选择
TSLint、ESLint 的区别
TS 已经建议使用 ESLint 了
对 TS 的认识,项目中是否使用
那必须使用了
介绍一些开源框架的原理
Koa、Axios、Vue、React、Taro 等
对开源框架的一些贡献
先吹下我的前端 100 问,再虚心的表示下后续对开源框架做些贡献
介绍我开发的性能监控 SDK、行为埋点 SDK 的工作、背景、遇到的问题等
我的业务问题,介绍了下整体的架构、遇到的一些难点、解决方案等
性能监控的一些实现原理,包括异常、网络请求、加载时间等
业务问题,吹就完事了
介绍下灰度功能
聊了下业务场景,实现原理,迭代优化的过程
对于后端的数据收集落库、web 搭建等的认识
不是主要开发,但是还是有些参与和了解
其他的项目难点
聊了下 SDK 的缓存优化
介绍下写博客和公众号的初衷、运营、推广等
主要还是提升自己,聊了下运营模式
二面
和一面一样都是聊项目,但是换了一个方向切入,主要还是根据简历上的点去深入提问
小程序的技术架构和方案、小程序的出现主要解决什么问题?
包含小程序容器、渲染引擎和 JavaScript 引擎。UI 层运行在 WebView 中,而逻辑层运行在独立的 JS 引擎中。
降低获客成本、打通跨端
view 层、js 层分别在哪里、怎么通信 ?
业务逻辑的 JS 在独立的 JavaScript 引擎(ServiceWorker)中,每个页面的 view 和 css 运行在各自独立的 webview 里面,页面之间是通过函数 navigateTo 进行页面的切换;
JS 层和 view 层通过消息服务 MessageChannel 进行通信
Taro 和其他小程序框架的横向对比,如何选型
Taro、uni-app、kbone、WePY、mpvue
Taro 的一些好用的点和不好用的点,聊下想法
一些特性不支持,不过随着 Taro 的升级也在解决
Taro 本身的限制
对 React 的语法支持有限,比如不能使用 Array#map 之外的方法操作 JSX 数组
React 代码转成小程序代码的原理
编译器修改和运行时修改,同时配合 babel 做编译、转译
Babel 的转换过程,比如把 JSX 的 map 转成 wxml
根据 AST 中的 JSXElement 生成对应的数据结构,比如
oddNumbers.map(number => <Text onClick={this.handleClick}>{number}</Text>)
生成的数据结构是
{
type: 'element',
tagName: 'text',
attributes: [
{ bindtap: 'handleClick' },
{ 'wx:for': '{{oddNumbers}}' },
{ 'wx:for-item': 'number' }
],
children: [
{ type: 'text', content: '{{number}}' }
]
}
再根据这个结构转成 wxml 就好了,可以参考 himalaya[3] 的代码
真实数据和缓存的竞争如何处理,第一次如何处理,第二次有更新如何处理
优先使用缓存、真实数据替换缓存等
npm 版本号 ^ ~ 的区别
- 脱字符(^)来限定所安装模块的主版本号
- ^1.2.1 代表的更新版本范围为 >=1.2.1 && < 2.0.0,即 1.x
- ^0.2.1 代表的更新版本范围为 >=0.2.1 && < 0.3.0,即 0.2.x
- ^0.0.2 代表的更新版本范围为 0.0.2(相当于锁定为了0.0.2版本),即 0.0.2
- 波浪号(~)是限定模块的次要版本
~1.5.1允许安装版本号大于1.5.1但小于1.6.0版本的模块,即 1.5.x
~0.5.1允许安装版本号为0.6.0,即0.5.x
怎么发 beta 版本
npm publish --tag beta
埋点数据上报的方案
Ajax 请求、img、script
图片方案的原理和优势
img 天然支持跨域;跨域友好、不占用 Ajax 请求、执行无阻塞
埋点上报数据的设计
介绍了下抽象数据模板,如何对不同业务场景进行拆分
介绍下曝光埋点
埋点数据服务端相关的逻辑
异常数据的排查
是否做过 SQL 表查询
写过的最复杂 SQL 查询
介绍下技术运营
最近在看的书
三面、四面
这两轮面试聊得比较轻松,主要聊些项目、规划、思考这些方面
有亮点的项目
写的 SDK 对比同类产品的优势
遇到的问题以及有哪些反思
技术规划
技术的优势和不足
个性、协作方面的优点和缺点
工作地点选择
工作节奏
抗压能力怎么样
HR 面
HR 面还是需要准备下,不能在最后一步功亏一篑了
介绍最近几年的工作经验
换工作的原因
目前在看的工作机会
如何考虑未来发展
每家公司离职的原因
之前跳槽拿到哪些 offer
考虑工作机会的优先级(公司、团队、技术、薪资等排序)
成长特别快的公司和经历
生活、工作遇到的一些有挑战的地方
面对压力一般是怎么应对的
之前工作的绩效
团队中的定位、排名如何
字节
字节的话比蚂蚁少一轮技术面,一共是 3 轮技术面 + 1 轮 HR 面,全程是视频面试,其中比较难的是第 1、2 面,因为前 2 轮会有 3 道左右的笔试题,3 面就是聊聊项目比较简单,HR 面就完全和技术无关了,纯粹问些你的期望、离职原因等基本信息,没有一票否决权。
所以如果你打算面试字节的话,一定一定一定提前准备下笔试题,包括但不限于算法题、编程题、手写实现题等。
- 编程题可以看我的前端 100 问:Daily-Interview-Question[4]
- 算法题可以看瓶子君的算法营:JavaScript-Algorithms[5]
一面
这里介绍下遇到的手写题,其他的问题和项目关联,就不再重复了
下面这几道题目已经更新到了我的题库中,可以去那里查看解析,Daily\-Interview\-Question / 字节[6]
弹性盒子中 flex: 0 1 auto 表示什么意思
求最终 left、right 的宽度
<div class="container">
<div class="left"></div>
<div class="right"></div>
</div>
<style>
* {
padding: 0;
margin: 0;
}
.container {
width: 600px;
height: 300px;
display: flex;
}
.left {
flex: 1 2 500px;
background: red;
}
.right {
flex: 2 1 400px;
background: blue;
}
</style>
输出以下代码运行结果,为什么
如果希望每隔 1s 输出一个结果,应该如何改造?注意不可改动 square 方法
const list = [1, 2, 3]
const square = num => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(num * num)
}, 1000)
})
}
function test() {
list.forEach(async x=> {
const res = await square(x)
console.log(res)
})
}
test()
实现一个批量请求函数 multiRequest(urls, maxNum)
要求:
- 要求最大并发数 maxNum
- 每当有一个请求返回,就留下一个空位,可以增加新的请求
- 所有请求完成后,结果按照 urls 里面的顺序依次打出
二面
这一面主要对我之前写过的文章进行提问,找了一些文章中可以再深入的点进行提问
介绍原型鸡生蛋、蛋生鸡问题
可以看我之前的文章,深入探究 Function & Object 鸡蛋问题[7]
输出以下代码的结果
Object instanceof Function
Function instanceof Object
Object instanceof Object
Function instanceof Function
结果都是 true
手写深拷贝
可以看我之前的文章,面试题之如何实现一个深拷贝[8]
如何实现正则的深拷贝
可以看我之前的文章,Lodash是如何实现深拷贝的[9]
模拟实现 Array.prototype.splice
可以看我的题库,已经收录这道题了,第 158 题:如何模拟实现 Array\.prototype\.splice[10]
三面
前面两面通过之后,三面就比较简单了,主要就是聊项目,聊我之前做过的项目,亮点,之后的规划,以及加入团队之后所要做的项目
HR 面
比较简单,聊之前的经验,还有期望薪资之类的,没有蚂蚁 HR 的一票否决,整个过程还是比较轻松愉快
面试感想
先来说下大环境,感觉非常不好,就一二线互联网来说招人的没几家公司,裁员的、内部调整的、锁 HC 的确是一大堆,所以大家在换工作的时候一定不要裸辞,风险太大。
今年面试和往年感受有些不同,对于项目的重难点、亮点、个人在团队中做的贡献、对项目的 Owner 意识等比较关注,还有就是编程能力的考察会更多一些。
对于社招小伙伴来说,除了常规的 CSS / JS / 网络 / 浏览器 / 异步 / 框架 / 工程化等方面,还需要在以上说的这两方面多加准备准备,准备越充分,拿到的面试评价越高,能拿到的薪资也将越多,加油!!!
参考资料
[1]
第 154 题:弹性盒子中 flex: 0 1 auto 表示什么意思: https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/380
[2]
图解拼多多&leetcode14:最长公共前缀: https://github.com/sisterAn/JavaScript-Algorithms/issues/19
[3]
himalaya: https://github.com/andrejewski/himalaya/blob/master/src/stringify.js
[4]
Daily-Interview-Question: https://github.com/Advanced-Frontend/Daily-Interview-Question
[5]
JavaScript-Algorithms: https://github.com/sisterAn/JavaScript-Algorithms
[6]
Daily-Interview-Question / 字节: https://github.com/Advanced-Frontend/Daily-Interview-Question
[7]
深入探究 Function & Object 鸡蛋问题: https://github.com/yygmind/blog/issues/35
[8]
面试题之如何实现一个深拷贝: https://github.com/yygmind/blog/issues/29
[9]
Lodash是如何实现深拷贝的: https://github.com/yygmind/blog/issues/31
[10]
第 158 题:如何模拟实现 Array.prototype.splice: https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/384
❤️ 交流讨论欢迎关注公众号 「秋风的笔记」,主要记录日常中觉得有意思的工具以及分享开发实践,保持深度和专注度。回复"好友"可加微信,秋风的笔记常年陪伴你的左右。
「点赞、分享」是对作者最大的支持❤️