这段时间被阿里面试了两次,以下是这两次笔试的题目,题目本身不难,奈何实力不足,做题的时候容易怂,所以做得不是很好,最近反思之后,将题目重新做了一遍,答案仅为个人想法,测试用例都过了,但还有一定(是很大很大很大)的进步空间,先记录下来,有空的时候再进行二次复盘。
1.一个小时做出以下三道题
难度:两颗星(题目真的不难,就是当时有点紧张)
- 手写防抖(debounce),手写节流(throttle)
function debounce(fn, cb) {
let timer;
return function (...args) {
clearTimeout(timer);
timer = setTimeout(() => fn(args), delay);
};
}
function throttle() {
let timer;
return function (...args) {
timer = setTimeout(() => {
fn(args);
clearTimeout(timer);
}, delay);
};
}
-
获取嵌套数组深度。
说明:给定一个带嵌套的数组,实现一个方法可获取嵌套数组的最大深度,
数组无嵌套子数组,则返回0,有一层嵌套子数组则1,依此类推。
示例:
getArrayDeep([]); // 返回 0
getArrayDeep([[[[]]]]); // 返回 3
getArrayDeep([0, [2], [2, [3]]]); // 返回 2
// 以下的答案能过这三个案例,但是递归本身还是有问题。。。
function getArrayDeep(arr) {
let depth = 0;
if (!arr.length) return 0;
for (let i = 0; i < arr.length; i++) {
if (Array.isArray(arr[i])) {
depth = Math.max(depth, getArrayDeep(arr[i])) + 1;
}
}
return depth;
}
// PS:理论上凡是可以用递归的地方都能用栈实现,奈何我递归学的不是很好,用栈怎么实现先欠着债,总有一天我会还上的
// 接下来是还债时间,按照上文的递归总算是把对应的栈方法写出来了。。。
// 写完之后三个样例都能通过,但是。。。逻辑上还是错的,比如下面这个样例
//e.g. getArrayDeep([2, 3, [2, 3, 4, [2, 3], [4, 5]]])
function getArrayDeep(arr) {
let depth = 0;
let temp = 1;
if (!arr.length) return 0;
let stack = [];
for (let i = 0; i < arr.length; i++) {
if (Array.isArray(arr[i])) {
temp = 1;
stack.push(...arr[i]);
while (stack.length) {
let demo = stack.pop();
if (Array.isArray(demo)) {
temp++;
stack.push(...demo);
}
}
}
depth = Math.max(temp, depth);
}
return depth;
}
分析:栈方法其实就是模仿了递归的过程,从栈方法中很容易发现,上面的解法计算的是每个子数组中的数组数量,当子数组中有多个并列的数组时,问题就会出现(哭嘁嘁😭)
// 重新再来,又欠债了
// 晚上回来之后反思了一下,需要返回的是每个子数组中的最深镶嵌数组,所以需要的其实递归的是数组的Math.max
function getArrayDeep(arr) {
if (!arr.length) return 0;
let stack = [];
let depth = 0;
for (let i = 0; i < arr.length; i++) {
if (Array.isArray(arr[i])) {
stack.push(arr[i]);
}
}
stack = stack.map((item) => Math.max(getArrayDeep(item), depth) + 1);
return Math.max(...stack);
}
// 还是老样子,在想着栈的方案,想着想着突然想到了flat方法,咦,不是刚刚好这个问题的反解嘛,于是就有个flat的简洁版方案
function getArrayDeep(arr) {
let temp = 0;
if (!arr.length) return 0;
while (Array.isArray(arr) && arr.some((item) => Array.isArray(item))) {
temp++;
arr = arr.flat(1);
}
return temp;
}
// 顺便附上自定义flat的代码,本质还是递归
function flat(arr, d = 1) {
return d > 0
? arr.reduce(
(pre, curr) =>
pre.concat(Array.isArray(curr) ? flat(curr, d - 1) : curr),
[]
)
: arr.slice();
}
感悟:很多问题看着很简单,仔细想想还是有很多值得推敲的地方,思考问题需要有一个全面性,按照这道题而言,最开始的解确实能够得到样例正确解,但并非完全正确,思考后发现第二种方法更加接近答案。还有就是要巧妙利用各种API,大佬们都帮我们封装好了为啥不用~
PS:栈方法先鸽,太复杂了,脑子暂时不够使😭😭😭,有肝出来的有缘人求分享~
-
实现一个 normalize 函数,能将输入的特定的字符串转化为特定的结构化数据。
// 字符串仅由小写字母和[,]组成,且字符串不会包含多余的空格。
// 示例一: ‘abc’ --> {value: ‘abc’}
// 示例二:’[abc[bcd[def]]]’ -> {value: ‘abc’, children: {value: ‘bcd’, children: {value: ‘def’}}}
// 默默吐槽一下当时由于紧张写了arr=arr.splice(0,1)的我,啊,社💩翻车现场,还有在reduce里面把函数中所有的pre都写成了obj的我。。。。。。 function normalize(str) { let arr = str.split("["); if (arr.length > 1) { arr.splice(0, 1); } let obj = {}; const len = arr.length; arr.reduce((pre, curr, index) => { pre.value = curr.replace(/[^\w]*/g, ""); // console.log(pre, index); if (index !== len - 1) { pre.children = {}; console.log(pre); return pre.children; } }, obj); return obj; }
2.20分钟做出以下三道题
-
问题:实现
calc
方法,统计各个 tag 出现的次数和对应的 name 值。
const array = [
{name: ‘articleA’, tags: [‘javascript’, ‘es6’, ‘css’]},
{name: ‘articleB’, tags: [‘animation’, ‘transform’, ‘css’]},
{name: ‘articleC’, tags: [‘javascript’, ‘currying’]}
];
console.log(calc(array, ‘javascript’));
console.log(calc(array, ‘css’));
输出数据如下:
javascript: 2, [articleA, articleC]
css: 2, [articleA, articleB]function calc(arr, tag) { if (!arr.length) return `${tag}: 0 []`; let count = 0; let nameArr = []; for (let i = 0; i < arr.length; i++) { if (arr[i].tags.includes(tag)) { count++; nameArr.push(arr[i].name); } } return `${tag}: ${count},[${nameArr}]`; }
-
问题:请编写一个JavaScript函数 parseQueryString,它的用途是把URL参数解析为一个对象
var url = “https://pd.alipay.com/#/product/productHome?catalogCode=GC&tabKey=GOC&roleType=GOC”
var paramObj = parseQueryString(url);
console.log(paramObj.catalogCode, paramObj.tabKey, paramObj.roleType); // GC GOC GOCfunction parseQueryString(url) { let [host, param] = url.split("?"); if (!param) return {}; let obj = {}; let arr = param.split("&"); for (let i = 0; i < arr.length; i++) { let [key, value] = arr[i].split("="); obj[`${key}`] = value; } return obj; }
-
问题:实现一个简单的模板渲染
给定一个模板和一个对象,利用对象中的数据渲染模板,并返回最终结果。
例如:
let template = '你好,我们公司是{{company}},我们属于{{group.name}}业务线,我们在招聘各种方向的人才,包括{{group.jobs[0]}}、{{group[“jobs”][1]}}等。let obj = {
group: {
name: “天猫”,
jobs: [“前端”, “后端”, “产品”]
},
company: ‘阿里巴巴’
}function render(tem, obj) { return tem.replace(/\{\{\s*(.+?)\s*\}\}/g, (value, $1) => new Function(`return this.${$1}`).call(obj); ); }