近期面试复盘

本文最后更新于:2021/08/09 , 星期一 , 23:41

滴滴

就记住这几个。

  1. react-router 动态路由

  2. Webpack 中的 loader 和 plugin 区别
    Loader 的作用是让 webpack 拥有加载和解析非 JavaScript 文件的能力。Plugin 是扩展 Webpack 的功能,在 webpack 运行的生命周期中。

  3. Chunk 和 bundle 的区别
    chunk 是打包过程中的文件,bundle 是打包的结果。

  4. Webpack 的构建优化
    可以看我另外一篇写的构建优化

  5. Hook:useEffect useRef useCallback useMemo
    解释了一下用法,原理。什么时候用。

  6. 描述 Redux 数据流
    单项数据流:dispatch(Action)->Reducer->Store.

  7. React-sugar 用过吗?
    没用过。

  8. React 是如何数据驱动视图的
    卡颂大佬的 React 源码解析

  9. Node 的事件循环(10 为分界线)
    看我摘抄淘宝前端团队的那篇文章《JavaScript 之事件循环》

  10. 强缓存协商缓存

    • 强缓存:cache- control 和 expiress
    • 协商缓存:last-modify 和 If-Modified-Since:和时间有关,时间不一致会有问题。Etag 和 If-None-Match:服务端先对文件生成唯一标识 ETag,在第一次请求的时候带回来,第二次请求的时候请求头会有 If-None-Match:ETag 值的形式,如果 ETag 不匹配就拿新资源,匹配就返回 304。
  11. 怎么判断啥时候该去请求最新的资源,啥时候去请求 service Worker
    这个没回答,因为不了解 ServiceWorker,然后跟面试官讲了一下我所知道的 serviceWorker,PWA 以及用 serviceWorker 实现的 mock 方案这些。
    具体可以看service Worker第十点的缓存管理,大概就是在 servicerWoker 的 install 阶段时,open 待版本号的 cache,版本号变了就会更新了。

  12. 实现深拷贝
    当时没实现出来,哈哈哈哈哈,只是面试官说了一下递归,遇到 object 就下一层这样的一个思路。因为但是只记得处理 Object

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
function deepClone(value, hashMap = new WeakMap()) {
if (value == undefined || typeof value !== 'object') {
return value;
}

if (value instanceof Date) {
return new Date(value);
}

if (value instanceof RegExp) {
return new RegExp(value);
}

const hashKey = hashMap.get(value);
if (hashKey) {
return hashKey;
}


const result = new value.constructor();
hashMap.set(value, result);
Object.keys(value).forEach((key) => {
result[key] = deepClone(value[key], hashMap);
})

return result;
}
  1. 数组去重
    哈哈哈哈哈,这个我也没实现。我比较皮的说了一句 Array.from(new Set()),然后面试官说不行。
    然后我就搞了个 Map,遍历全部全部元素,key 就是 array[i]。然后面试官问我这种方式遇到undefined怎么办,我说undefined是可以作为 key 的,之前手滑给过一次 undefined,然后引发了 bug 哈哈哈哈,然后又问我能不能存[1,2,3,[4,5]]的第三项,我当时不太确定能不能存,告诉面试官不确定。
1
2
3
4
5
6
7
8
9
10
11
12
13
function arrayNonRepeatfy(arr) {
let map = new Map();
let array = new Array();
for (let i = 0; i < arr.length; i++) {
if(map.has(arr[i])) {
map.set(arr[i], i);
} else {
map.set(arr[i], i);
array.push(arr[i]);
}
}
return array ;
}

不过这种不能应对[1,2,3,[4,5],5,[4,5]]去重。可以判断一下是Array.isArray(num)||(typeof num === "object" && num !== null),然后用 JSON.stringify 一下再存到 Map 里,在 has 判断的时候也先序列化一下。

  1. 实现一个 moment.format
    这个当时也没实现,也是仅仅实现了个不传 paramDate 和 formatStr 的最简单版本,只是跟面试官说了一下要想实现传入 formatStr 的这个,用正则会方便点。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
const format = (paramDate, formatStr) => {
const date = new Date(paramDate) || new Date();
const year = date.getFullYear();
const month = date.getMonth() + 1;
const day = date.getDate();
const week = date.getDay();
const hour = date.getHours();
const minute = date.getMinutes();
const second = date.getSeconds();

return formatStr
? formatStr.replace(
/Y{2,4}|M{1,2}|D{1,2}|d{1,4}|H{1,2}|m{1,2}|s{1,2}/g,
(match) => {
switch (match) {
case "YY":
return String(year).slice(-2);
case "YYY":
case "YYYY":
return String(year);
case "M":
return String(month);
case "MM":
return String(month).padStart(2, "0");
case "D":
return String(day);
case "DD":
return String(day).padStart(2, "0");
case "d":
return String(week);
case "dd":
return weeks[week];
case "ddd":
return "周" + weeks[week];
case "dddd":
return "星期" + weeks[week];
case "H":
return String(hour);
case "HH":
return String(hour).padStart(2, "0");
case "m":
return String(minute);
case "mm":
return String(minute).padStart(2, "0");
case "s":
return String(second);
case "ss":
return String(second).padStart(2, "0");
default:
return match;
}
}
)
: `${year}-${month}-${day} ${hour}:${minute}:${second}`;
};
  1. 实现一个符合 promise/A+的 promise。

    看我前段时间写的手撕 promise

  2. 看代码题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// 1.异步输出
//请写出输出内容
async function async1() {
console.log("async1 start");
await async2(); //等这个执行完。
console.log("async1 end");
}
async function async2() {
new Promise(function (resolve) {
console.log("promise1");
resolve();
}).then(function () {
console.log("promise2");
});
}

console.log("script start");

setTimeout(function () {
console.log("setTimeout"); //1.进hong
}, 0);

async1();

new Promise(function (resolve) {
console.log("promise3");
resolve(); //3].进微任务
}).then(function () {
console.log("promise4");
});

console.log("script end");
  1. 实现一个 sleep 函数,多种方式,比如 sleep(1000)

阻塞 js 执行就可以

1
2
3
4
5
6
7
8
9
10
11
12
13
const sleep = (num, fn) => {
let start = new Date().getTime();
while (new Date().getTime() - start < num);
fn();
};

const sleep = (num) => {
return new Promise((resolve) => {
setTimeout(() => {
resolve();
}, num);
});
};
  1. 合并两个有序整数数组,使之成为一个有序数组,function(arr, brr) ,假设 arr 长度刚好容纳所有数据
1
2
3
4
5
6
7
8
9
10
11
12
13
var merge = function (nums1, nums2) {
let nums1First = nums1.length - nums2.length - 1,
nums1Second = nums1.length - 1,
nums2First = nums2.length - 1;
while (nums1First >= 0 && nums2First >= 0) {
nums1[nums1Second--] =
nums1[nums1First] > nums2[nums2First]
? nums1[nums1First--]
: nums2[nums2First--];
}
nums1.splice(0, nums2First + 1, ...nums2.slice(0, nums2First + 1));
return nums1;
};

美团打车

  1. 实现 checkbox 组件,提供给其他人使用
  2. 看代码题
1
2
3
4
5
6
7
8
9
10
11
12
13
var name = "张三";
const people = {
name: "李四",
sayName() {
console.log(this.name);
},
};
// Q1
people.sayName();
const temp = people.sayName;
// Q2
temp();
// Q3 能否利用call/apply使输出结果为张三
  1. 给定一个数组,移除所有相邻相同数字,直到没有相邻相同数字为止。

Input:  [1, 2, 3, 3, 4, 4, 2, 5, 7, 7, 5, 6, 8, 1]
Output:  [1, 6, 8, 1]

1
2
3
4
5
6
7
8
9
10
11
const filter = (arr) => {
const res = [];
arr.forEach((item) => {
if (res[res.length - 1] === item) {
res.pop();
} else {
res.push(item);
}
});
return res;
};
  1. hash contentHash chunkHash 区别

hash:工程级别,修改任何一个文件都会导致所有文件 hash 改变

chunkHash:模块级别的,根据不同的入口文件(Entry)进行依赖文件解析、构建对应的 chunk,生成对应的哈希值。

contentHash:文件内容级别的,内容不同产生的 hash 就不同。