阿里 CBU 前端 1 - 4 面 + hr 面面经
呼...第二个阿里面的部门,总的来说体验挺好的。
(第一个是钉钉,没准备就面了,直接凉凉)
提前批 一面 某个晚上 8:30 90min
投了简历后的大概两三天后,某个晚上 8:30 就收到了一面的电话。
由于时间的久远,具体的问题记不太清了 😂 主要问到了以下这些方面吧。
项目部分
这里问的还算比较细,深入了一个点。这里面试官看到我简历写了自己实现了一个数据流的优化方案和用到了 Dva 就深入的问了这两个。
ES6 部分
- 继承的方式
- 没种继承方式的优缺点
- 介绍下 Object.assign() 和坑点
- 介绍下深浅拷贝
- 深浅拷贝的实现
- generator、Promise、async/await (这部分展开问了很多细节)
- Promise 异常捕获
- Promise 中断链式
- await 可以单独使用吗
- 请求(fetch、axios)
- (还有一些细节都是展开来聊的,年代太久远了不记得了 🤦♂️)
计网 + React + 其他
这里就是常规的面试题了...具体是啥真不记得了 😂
CSS 部分
哭了 这块问了很多我觉得比较冷门的东西吧
- 介绍下 flex
- flex 的属性 (给了个实际的需求用 flex 实现)
- flex 的主轴方向怎么定义
- flex 的排列顺序受到 location 的影响吗(面试官的意思是地方...就是真的地域的地方...这里我感觉应该是想拓展到 RTL?)
- flex 在移动端的表现 是否会受到屏幕颠倒而转变(黑人问号)
- 还有很多冷门的 😂
软件工程部分
面试官看了眼我的专业 哟 软件工程的 那就问问软件工程的问题吧...然后就开始了漫长的软件工程之旅 😢
- 说下项目内是怎么从 0 到 1 实现一个项目,具体的流程
- 需求分析、审批阶段
- 开发阶段
- 测试阶段
- 验收阶段
- 交付阶段
- (大概说了这个几个 😂,都是从项目实际出发去聊)
- 然后还聊了下 项目内人员的分工 负责的职责啥的
我记得一面就问了这些吧 😂,面试官看时间也挺晚了,然后就说后续会补一个笔试啥的,会在这两天内发。
提前批 一面 笔试 2.29 2:00 - 4:00
一面后的三天内,面试官打电话来约了个笔试时间。
笔试是邮件发题目,规定时间内做完然后发回去。
一共是三道题 需要自行设计测试用例
笔试题一
给定不同面额的硬币 coins 和一个总金额 amount
编写一个函数来计算可以凑成总金额所需的最少的硬币个数
🥬🐔 的答案
虽然这类题目做了 n 次,但算法一直是弱项 哎...
function coinChange(coins, amount) {
let ans = new Array(amount + 1).fill(Infinity);
ans[0] = 0;
for (let i = 1; i <= amount; i++) {
for (let coin of coins ) {
if (i >= coin) {
ans[i] = Math.min(ans[i], ans[i - coin] + 1);
}
}
}
return ans[amount] === Infinity ? -1 : ans[amount];
}
// 测试
coinChange([1, 2, 5], 11); //3
coinChange([2, 4], -1) // -1
coinChange([1, 2, 4, 5, 10], 100) //10
/*
测试
数据测试1:
coins = [1, 2, 5]
amount = 11;
预期输出 3
coinChange([1, 2, 5], 11)
实际输出3
数据测试2:
coins = [2, 4]
amount = 3;
预期输出 -1
coinChange([2, 4], -1)
实际输出 -1
数据测试3:
coins = [1, 2, 4, 5, 10]
amount = 100;
预期输出 3
coinChange([1, 2, 4, 5, 10], 100)
实际输出 10
*/
笔试题二
/**
* 价格数组转换成可读性更好的文本序列
* 说明:有个数组,内部是。
* 示例:
* var input = [
* {
* "moqPe": 5,
* "pricePe": 12.85
* },
* {
* "moqPe": 15,
* "pricePe": 11.36
* }
* ]
* var output = rangeStringify(input);
*
* // output: "¥12.85 (5-15); ¥11.36 (≥15个)"
*/
🥬🐔 的答案
这里就直接边想边写了 有些写法也没有怎么优化 😂
function rangeStringify(arr) {
// 验证参数有效性
if (arr.length === 0) return [];
// 参数初始化
let resultTmp = '';
const arrLen = arr.length;
// 比较函数 自定义比较规则
const compare = (x, y) => {
if (+x.moqPe < +y.moqPe) {
return -1;
} else if( +x.moqPe > +y.moqPe) {
return 1;
} else {
return 0;
}
}
// 每一项格式化为字符串
const dataToString = ({ currentMoqPe, pricePe, index, nextMoqPe }) => {
// 判断最后一项
if (index === arrLen - 1) {
return "¥" + pricePe + " (" + "≥" + currentMoqPe + "个)";
} else {
return "¥" + pricePe + " (" + currentMoqPe + "-" + nextMoqPe + ")";
}
}
//数组处理 排序
arr.sort(compare);
//遍历数组生成结果数组
const result = arr.map((item, index, currentArr) => {
/*item数据格式
{
moqPe: 5, // number | string
pricePe: 11.36, // number | string
}
*/
resultTmp = dataToString({
currentMoqPe: item.moqPe,
pricePe: item.pricePe,
index,
nextMoqPe: index === arrLen - 1 ? 0 : currentArr[index + 1].moqPe,
});
return resultTmp;
})
// 结果数组转为字符串
let returnResult = result.join("; ");
return returnResult;
}
//第一组
let input = [{
"moqPe": 5,
"pricePe": 12.85
},{
"moqPe": 15,
"pricePe": 11.36
}];
let output = rangeStringify(input);
console.log(output);
// 第二组
input = [{
"moqPe": 5,
"pricePe": 12.85
}, {
"moqPe": 6,
"pricePe": 13.2323
}, {
"moqPe": 15,
"pricePe": 11.36
}];
output = rangeStringify(input);
console.log(output);
//第三组
input = [
{
"moqPe": 20,
"pricePe": 20.1
},{
"moqPe": 5,
"pricePe": 12.85
}, {
"moqPe": 15,
"pricePe": 11.36
}, {
"moqPe": 4,
"pricePe": 10.0
}]
output = rangeStringify(input);
console.log(output);
// 第四组
input = [{
"moqPe": 5,
"pricePe": 12.85
}]
output = rangeStringify(input);
console.log(output); //"¥12.85 (≥5个)"
// 测试
//
/*
测试数据1:
input1 = [{
"moqPe": 5,
"pricePe": 12.85
},{
"moqPe": 15,
"pricePe": 11.36
}]
预期输出:"¥12.85 (5-15); ¥11.36 (≥15个)"
实际输出:"¥12.85 (5-15); ¥11.36 (≥15个)"
测试数据2:
input2 = [{
"moqPe": 5,
"pricePe": 12.85
}, {
"moqPe": 6,
"pricePe": 13.2323
}, {
"moqPe": 15,
"pricePe": 11.36
}]
预期输出:"¥12.85 (5-6); ¥13.2323 (6-15); ¥11.36 (≥15个)"
实际输出:"¥12.85 (5-6); ¥13.2323 (6-15); ¥11.36 (≥15个)"
测试数据3:
input3 = [
{
"moqPe": 20,
"pricePe": 20.1
},{
"moqPe": 5,
"pricePe": 12.85
}, {
"moqPe": 15,
"pricePe": 11.36
}, {
"moqPe": 4,
"pricePe": 10.0
}]
预期输出: "¥10 (4-5); ¥12.85 (5-15); ¥11.36 (15-20); ¥20.1 (≥20个)"
实际输出: "¥10 (4-5); ¥12.85 (5-15); ¥11.36 (15-20); ¥20.1 (≥20个)"
测试数据4:
inpur4 = [{
"moqPe": 5,
"pricePe": 12.85
}]
预期输出:"¥12.85 (≥5个)"
实际输出:"¥12.85 (≥5个)"
*/
笔试题三
/*
* 字符串隐藏部分内容
* 说明:实现一个方法,接收一个字符串和一个符号,将字符串中间四位按指定符号隐藏
* 1. 符号无指定时使用星号(*)
* 2. 接收的字符串小于或等于四位时,返回同样长度的符号串,等同于全隐藏,如 123,隐藏后是 ***
* 3. 字符串长度是大于四位的奇数时,如 123456789,隐藏后是 12****789,奇数多出来的一位在末尾
* 示例:
* mask('alibaba', '#'); // a####ba
* mask('85022088'); // 85****88
* mask('hello'); // ****o
* mask('abc', '?'); // ???
* mask('阿里巴巴集团', '?'); // 阿????团
*/
🥬🐔 的答案
function mask(str, char) {
// 验证参数有效性
if (arguments.length === 0) {
console.log("请输入参数");
return "";
}
if (str ==="") return "";
// 无指定时用 * 号
char = char === undefined ? '*' : char;
/**
* 接受需要生成的字符和长度
* @param char
* @param len
* 返回目标字符串模版
*/
const tmpCreater = (char, len) => new Array(len).fill(char).join("");
// 获取字符串长度
let strLen = str.length;
// 小于等于4位直接返回
if (strLen <= 4) return tmpCreater(char, strLen);
// 获取基准Index
let pivotIndex = parseInt((str.length - 2) / 2, 10) - 1;
// 转换为字符数组
let strArr = str.split("");
// 替换字符串
strArr.splice(pivotIndex, 4, tmpCreater(char, 4));
// 返回目标字符串
return strArr.join("");
}
mask('alibaba', '#'); // a####ba
mask('85022088'); // 85****88
mask('hello'); // ****o
mask('abc', '?'); // ???
mask('阿里巴巴集团', '?'); // 阿????团
mask('abcdefgh123456789','·') //abcdef····3456789
mask('hg') // **
mask("") // ""
mask() // 控制台打印:请输入有效参数
/*
测试:
测试数据1:
mask('alibaba', '#'); // a####ba
预期输出:a####ba
实际输出:a####ba
测试数据2:
mask('85022088'); // 85****88
预期输出:85****88
实际输出:85****88
测试数据3:
mask('hello'); // ****o
预期输出: ****o
实际输出: ****o
测试数据4:
mask('abc', '?')
预期输出:???
实际输出:???
测试数据5:
mask('阿里巴巴集团', '?')
预期输出:阿????团
实际输出:阿????团
测试数据6:
mask('abcdefgh123456789','·')
预期输出:abcdef····3456789
实际输出:abcdef····3456789
测试数据7:
mask('hg')
预期输出:**
实际输出:**
*/
三道笔试实际的时间用了一个小时?然后后面大部分时间都在验证数据啥的 🤦♂️ 然后就提交了
总的来说题目还是挺简单的 😂。
提前批 二面 某个周四 5:30 60min
距离笔试过后的一个星期吧,周二下午就收到了二面的面试官约时间,恰巧那两天刚好满课 噗,就约了周四。
二面的话基本上都是聊的项目部分,可能我写的项目比较多 😂
- 介绍下项目
- 项目的难点和怎么解决(这块就重点聊)
- 项目优化
- 项目业务的理解 技术的选择
- 分工情况
整个二面的话还是聊简历写的和项目的技术点比较多,然后还有对业务的思考。
提前批 三面 60min
过了二面的两个多星期左右,就接到三面的电话
常规的开头,还是介绍自己和项目,然后每个项目都深入地去聊
聊到了项目中的高并发怎么在前端优化,给一些具体的优化方案
然后还问到了一些项目的具体技术细节。
平时怎么学习前端 怎么看待目前的前端
未来五年内的目标计划
交叉面 四面 50min
三面后过了一个星期就约四面了,据说好像是交叉总监面 噗。
这面问的就是偏向于整体了,技术细节基本就没什么了。
- 项目技术选型 为什么要这么选
- 项目难点 有没有沉淀解决方案
- 为什么选择前端
- 平时的学习方式 有没有系统的学习规划
- 未来的目标 怎么实现
- 然后就是一些闲聊
HR 面 3.30 晚上 7:30 40min
交叉后过了几天 HR 面在晚上突然打来然后就开始了。
- 自我介绍 & 大学的经历
- 你在项目团队中的位置
- 团队间人员配置怎么沟通
- 团队发生矛盾你是怎么处理
- 自己的不足
- 你觉得最欣赏的一个人
- 工作地点怎么看待
- 有没有其他 Offer
- 微信和阿里同时 Offer 怎么选择
面完了 HR 说大概一个星期内答复。
然后偷偷问了内推人,说一切总体下来都很好,说安心等 Offer。
呼....阿里的算是告一段落了。
本文使用 mdnice 排版