分享一下这两个月找暑期实习面试前端岗的经历。先说个人情况,因为平时没事爱好折腾,简历上比较亮眼的算是项目经历,GitHub 上星星相对来说比较多。基础还行,算法渣。
我知道自己算法渣的了,所以寒假春招之前有在刷Leetcode。还好前端出现的算法题好像不多,面试期间遇到的编程题都能在规定时间内解出答案。有些题目可能纯粹就是为了考你,但是为了能找到工作还是得刷题。
刷题不一定要按顺序刷,更重要的是刷过的题要理解,要题目变化之后还能解出来。可以一个个点刷,比如说连着做几题二分查找。
面试公司及进度
- 腾讯(offer)
- 字节跳动(HR 面过了,HR说在申请offer中)
- 网易游戏(投完简历就石沉大海了)
下面是面经,靠回忆,问题不全。
腾讯
腾讯有站长@0x0001 内推,3月2日晚上8,9点投的简历,然后光速被捞,半小时不到就接到了电话约面试。第一面是PCG。然后一路坎坷,最后去了CSIG。
PCG
- 自我介绍
- 问项目, 印象最深刻的项目
- 假如要实现一个用户登录要怎么做
- 有没有听说过或者用过JWT, 说说它和Cookie之间相对的优缺点
- 因为项目中用的Vue,所以面试官问了Vue实现响应式的原理
- 错误处理
- 埋点, 打log, window.onerror
编程题(在线编程需要翻墙)
function sum(input) {
// TODO: 在这里编写代码
const rows = input.split('\n'); // split line
function addRow(row) {
/**
* @param row {string} every row of the csv
* @returns {number} 单行求和
*/
return row.split(',')
.filter(numStr => numStr.length > 0)
.map(numStr => numStr.replace(/[A-Za-z]/g, ""))
.filter(numStr => numStr.length >0)
.map(i => parseInt(i, 10))
.filter(num => num % 2 !== 0)
.reduce((acc, cur) => acc += cur)
}
const result = rows.map(row => addRow(row)).reduce((acc, cur) => acc += cur);
return result
}
assert.equal(sum(`0x11,av,8D,000666WHh\nT3,2o19,M16A4,996icu`), 233); // UpperCase
assert.equal(sum(`0x11,av,,000666hhh\nT3,2o19,M16A4,996icu`), 233); // contain empty string
assert.equal(sum(`0x11,av,8d,000666hhh\nT3,2o19,M16A4,996icu\n0x11,av,8D,000666WHh`), 244); // more line
题目是二选一,这道题是有背景故事,大概就是小明要破译一个csv格式的密码,过滤掉字母然后把奇数数字加起来就是最终结果。
另外一道题是手写Promise.race, 面试官立刻删掉了就没有保存。
问题答的不好,然后就挂了。
CDG
- JS有哪些数据类型
- JS的继承方式有哪些
- 问项目,项目问的比较多,不写了。
- iCal 转换这块是怎么做的,后续有在用吗(blog上的文章,大一的时候瞎搞的一个python脚本)
- 用户白屏要怎么处理
- 错误收集
- HTTP 缓存
- Service Worker的生命周期
面完自我感觉良好,秒挂,然后又秒被捞。
QQ看点直播团队
一面
- 自我介绍
- 问项目
- TypeScript
- 平时学习的途径
- 在项目中做了什么性能优化
- 了解CDN吗?
- Webpack 构建中在文件名加hash的意义是什么
- HTTP Cache
- 页面中出现不应该出现的广告可能的原因
- HTTPS
- Web App中的常见攻击手段还有防范方法
- 什么时候能来实习
- 了解一些个人情况
QQ屏幕共享编程,不能用搜索引擎查。这两题我看网上很多人都被考了,从题库上抽的?
// 1. 页面内有一个正方形元素,实现对其拖拽和放下,需要考虑窗口的边界情况。
// 2.实现大整数相加算法,两个数用字符串模拟函数原型:function add(a, b) {}
第一题我的做法是一个releative容器,正方形position absoulte然后监听mouse(up, down, leave, move) 等事件就好了,不贴代码。
第二题
const {expect} = require('chai');
function add(x, y) {
const rx = Array.from(x).reverse();
const ry = Array.from(y).reverse();
const xLen = x.length;
const yLen = y.length;
let longArr = ry;
let shortLen = rx.length;
if(rx.length > ry.length) {
longArr = rx;
shortLen = ry.length;
}
const result = [];
let carray = 0, i = 0;
for(i=0;i<shortLen;i++) {
let r = parseInt(rx[i], 10) + parseInt(ry[i], 10) + carray;
if (r >= 10) {
r = r % 10;
carray = 1;
} else {
carray = 0
}
result.push(r);
}
for (;i<longArr.length;i++) {
let r = parseInt(longArr[i], 10) + carray;
if(r >= 10 ) {
carray = 1;
r = r % 10;
} else {
carray = 0;
}
result.push(r);
}
return result.reverse().join('');
}
expect(add('123', '123')).to.equal('246');
expect(add('123', '1234')).to.equal('1357');
expect(add('123456789', '345678912345')).to.equal('345802369134');
expect(add('123456789102', '34567891299345')).to.equal('34691348088447');
expect(add('2199023255552', '2199023255552')).to.equal('4398046511104');
二面
- vdom 了解吗,解决了什么问题?
- DOM Diff中会有什么特殊逻辑
- 一张图片的请求过程
- 白屏的可能原因
- 无原因的出现白屏怎么解决
- 错误收集
- 兼容性问题如何解决
- CDN 有了解吗?
- HTTP 的 Cache
- cookie,sessionStorage,localStorage
- TCP 握手挥手
- Web浏览器安全方面的攻击手段和防范
三面leader面(技术)
- ES6 class 和 ES5 class 有何差别
- 实现垂直居中的方式
- 前端怎么发请求
- 什么情况下会跨域
- XHR要怎么写
- XHR 的readyState有几种状态分别代表什么意思
- XHR readyState 为2时能拿到什么
- 浏览器的渲染模式(当时懵逼,反问的时候问知道他说的是
document.compatMode
- 有写过后端吗? (我回答了Koa
前面的问题还行,后面开始问我Koa里怎么setHeader之类的具体的API,不记得(平时都现查文档)开始疯狂白给。之后了解一些个人情况。问最早什么时候能去实习。
还有一道编程题,最长回文子串,动态规划
几天之后挂了。
WXG 微信小程序
一面
上来先编程题三道
/*
* 1. 实现一个函数,接受数组作为参数,数组元素为整数或者数组(数组里面还可能有数组),函数返回扁平化后的数组。要求给出不使用递归、不使用字符串处理的解法
* 如:输入 [1, [2, [ [3, 4], 5, []], 6]],输出 [1, 2, 3, 4, 5, 6]
*/
function flatten(arr) {
let result = [];
for(let element of arr) {
if(!Array.isArray(element)) {
result.push(element);
} else {
result = result.concat(...element);
}
}
let idx = result.findIndex(e => Array.isArray(e));
while(idx !== -1) {
result = [...result.slice(0, idx-1)].concat(result[idx]).concat(result.slice(idx+1));
idx = result.findIndex(e => Array.isArray(e));
}
return result;
}
/*
* 2. 假设有一个升序数组,经过不确定长度的偏移,得到一个新的数组,我们称为循环升序数组。(例:[0,3,4,6,7] 可能变成 [6,7,0,3,4])。给定一个数字和一个循环升序数组,判断这个数字是否在这个数组内,在的话返回 true,否则返回 false。要求时间复杂>度 O(logN)
*
* 示例 1:
* 输入:nums = [6,7,0,3,4], target = 0
* 输出:true
*
* 示例 2:
* 输入:nums = [6,7,0,3,4], target = 2
* 输出:false
*/
function search(nums, target) {
const len = nums.length;
if (len <= 3) return nums.indexOf(target) >= 0;
let mid = Math.floor(len / 2);
let left = 0, right = len - 1;
if (nums[mid] === target) return true;
if (nums[mid] < target) {
if (target < nums[len - 1]) {
return search(nums.slice(mid + 1), target);
} else {
return search(nums.slice(0, mid - 1), target);
}
} else {
if (target < nums[len - 1]) {
return search(nums.slice(mid + 1), target);
} else {
return search(nums.slice(0, mid - 1), target);
}
}
}
/*
* 3. 设计一个函数,用于测试请求一个 URL 的平均耗时。要求可以设置总的请求次数以及并发请求个数。假设环境是小程序,使用的接口是 wx.request ,不考虑请求失败的情况。
*
* @synopsis 测试网络请求平均耗时
*
* @param URL 请求的地址
* @param count 请求的总次数,取值范围 >= 1
* @param concurrentCount 并发请求限制个数(即最多只能同时发起多少个请求)。取值范围 >=1
*
* @returns 一个 Promise 对象,resolve 平均耗时
*/
// wx.request 调用示例
// wx.request({
// url: 'https://qq.com',
// success() {
// // 请求完成
// }
// })
async function measureTime(URL, count, concurrentCount) {
if (concurrentCount < count) throw new Error('count should be greater or equal to concurrentCount');
const round = Math.ceil(count / concurrentCount);
function mesureOnce(url) {
const startTime = Date.now();
return new Promise((resolve) => {
wx.request({
url,
success() {
resolve(Date.now() - startTime);
}
})
})
}
let rest = count;
let timesResult = [];
for (let i = 0; i < round; i++) {
let promiseArr;
if (rest >= concurrentCount) {
promiseArr = new Array(concurrentCount).fill(mesureOnce(URL));
rest -= concurrentCount;
}
else {
promiseArr = new Array(rest).fill(mesureOnce(URL));
rest = 0;
}
const times = await Promise.all(promiseArr);
timesResult = timesResult.concat(times);
}
return (timesResult.reduce((acc, cur) => acc += cur) / timesResult.length);
}
- setTimeout 有可能不准吗
- Map WeakMap
- cookie session
- cookie 的使用
- 问项目
- service worker 怎么工作
- (service) worker 可以调用 localSotrage吗?
- service worker 要怎么向服务器请求资源
- 项目中的解决的技术难点
一面完,面试官口头说过了,但是说我简历太简单了,可能后面的面试官看不上,叫我改简历。之后还特地发邮件过来叫提醒我可以放些什么东西上建立,叫我改完简历之后告诉他。这个面试官真好人。
改好简历之后迎来了二面
二面面试官上来叫我介绍项目。我介绍完了。面试官什么问题都没问,然后进入反问环节。然后挂掉。
CSIG
一面
- JS中的作用域
- ES6箭头函数了解吗?
- 闭包是什么,应用场景?
- Promise是什么,具体怎么使用
- 防抖和节流
- JS的继承方式
- 浏览器的事件流
- ES5 如何实现ES6 class
- CSS 动画
- BFC有了解吗?
- Vue的响应式原理
- HTTP协议状态码的含义能说多少说多少
- TCP UDP 的区别和实际应用
- HTTPS 原理 TLS的握手过程
- Web App全方面的攻击手段和防范
- service worker 生命周期
- Docker 和 虚拟机有什么区别(CGroup Namespace)
- 有使用过Linux命令行吗?
- 查看系统资源占用你会使用什么命令
- 在docker内使用top你查看到的进程号是宿主机的进程号还是Docker内的进程号(PID 有 Namespace)
二面
突然来的视频面试。
- 问项目
- JS的基本数据类型
- JS实现异步的原理
- Redux或者Vuex的作用是什么
- Vue怎么向父组件传值
- Node.js 不适合用在什么场景
- 如果Node.js 中需要一个长时间的运算,但不要求实时。可以用什么方式解决
- 为什么会在项目中使用Docker
- 如何防范 Web 安全攻击
- 简单的几段JS脚本,要我说出运行结果(Promise, 异步之类的
三面
- 问项目
- 为什么会选择用Node.js
- Node.js 学的怎么样
- 你为什么会选择前端
- 简历上有一些项目只有几颗星,为什么会选择放上去
- 从项目中学到什么
- 平时从什么途径学习
- 从记录上看,你的面试经历坎坷,你觉得你的问题出现在什么地方
- 实习时间是7月?
- 学校会不会不让出来
HR面
基本上就问一下个人情况,聊聊人生,确认实习地点深圳。有一个问题你遇到过的最大的挫折是什么?
虽然说投简历的时候觉得没什么,但是真正接到电话的时候还是有点紧张的。所以面试过程中的语言组织有些混乱(后面几次面试开了电话录音,重听了)。三面的时候面试官告诉我说,我的面试记录里面几个面试官对我技术侧的评价都是不错的,就是语言沟通方面是所有面试官都觉得欠缺的一项。觉得有一些地方可以提前组织一下语言吧,比如说自我介绍和项目的介绍,这两块都会问的很多,流畅地说出来会好很多。
知识方面,不面试不知道他问什么,面完恶补就完了。简历上的东西不要给自己挖坑。面CSIG之前跟@feng学了点经验,避免一问一答,在擅长的点要多引导面试官,别被面试官把自己带入坑。
feng 然后面试的话尽量避免一问一答吧,问到自己熟悉的可以多给面试官展现一些但是要适可而止,别给自己挖坑,问到知识盲区(大佬都是没有盲区的,我就不一样了,问啥啥不会)就诚恳一点
大佬说的对!