每日的知识积累,包括 1 个 Ts 类型体操,两个 Leetcode 算法题,三个前端八股文题,四个英语表达积累。
1. 一个类型体操
类型体操题目集合 Diff
获取两个接口类型中的差值属性。
例如:
type Foo = {
a: string;
b: number;
};
type Bar = {
a: string;
c: boolean;
};
type Result1 = Diff<Foo, Bar>; // { b: number, c: boolean }
type Result2 = Diff<Bar, Foo>; // { b: number, c: boolean }
分析
最终的结果由三个部分组成:T 中有但是 U 中没有;U 中有但是 T 中没有;或者它们都有但是值不相同的。然后使用 & 链接起来即可。
尝试写出
type Diff<U extends {}, T extends {}> = {
[P in keyof T as P extends keyof U ? never : P]: T[P];
} & {
[P2 in keyof U as P2 extends keyof T ? never : P2]: U[P2];
} & {
[P3 in keyof U as P3 extends keyof T
? U[P3] extends T[P3]
? never
: P3
: never]: U[P3];
};
简写方式
可以包一层,把这个写的更漂亮一些。
type DiffX<U, Y> = {
[P in keyof Diff<U, Y>]: Diff<U, Y>[P];
};
测试用例
type Result1 = {
[P in keyof Diff<Foo, Bar>]: Diff<Foo, Bar>[P];
}; // { b: number, c: boolean }
type Result2 = Diff<Bar, Foo>; // { b: number, c: boolean }
参考答案
type MyExclude<T, K> = T extends K ? never : T;
type Diff<O extends {}, O1 extends {}> = {
[P in MyExclude<keyof O, keyof O1> | MyExclude<keyof O1, keyof O>]: (O &
O1)[P];
};
经验总结
- 第一个经验:
[P in MyExclude<keyof O, keyof O1> | MyExclude<keyof O1, keyof O>] - 第二个经验:
(O & O1)[P]
2. 两个 Leetcode 题目
刷题的顺序参考这篇文章 LeeCode 刷题顺序
2.1 [54] 螺旋矩阵
给你一个 m 行 n 列的矩阵 matrix ,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。
示例 1:
输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出:[1,2,3,6,9,8,7,4,5]
示例 2:
输入:matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
输出:[1,2,3,4,8,12,11,10,9,5,6,7]
提示:
m == matrix.length
n == matrix[i].length
1 <= m, n <= 10
-100 <= matrix[i][j] <= 100
尝试实现:
/**
* @param {number[][]} matrix
* @return {number[]}
*/
var spiralOrder = function (matrix) {
let dir = 1; // 1 2 3 4
const m = matrix.length;
const n = matrix[0].length;
const mn = m * n;
const rst = [];
let i = 0;
let j = -1;
for (let k = 0; k < mn; k++) {
// 尝试向右
if (dir === 1) {
if (matrix[i] && typeof matrix[i][j + 1] !== "undefined") {
j++;
rst.push(matrix[i][j]);
matrix[i][j] = undefined;
continue;
} else {
dir = 2;
}
}
// 尝试向下
if (dir === 2) {
if (matrix[i + 1] && typeof matrix[i + 1][j] !== "undefined") {
i++;
rst.push(matrix[i][j]);
matrix[i][j] = undefined;
continue;
} else {
dir = 3;
}
}
if (dir === 3) {
if (matrix[i] && typeof matrix[i][j - 1] !== "undefined") {
j--;
rst.push(matrix[i][j]);
matrix[i][j] = undefined;
continue;
} else {
dir = 4;
}
}
if (dir === 4) {
if (matrix[i - 1] && typeof matrix[i - 1][j] !== "undefined") {
i--;
rst.push(matrix[i][j]);
matrix[i][j] = undefined;
continue;
} else {
dir = 1;
}
}
if (dir === 1) {
if (matrix[i] && typeof matrix[i][j + 1] !== "undefined") {
j++;
rst.push(matrix[i][j]);
matrix[i][j] = undefined;
continue;
} else {
return rst;
}
}
}
return rst;
};
我的思路:
- 首先走过的路会变成墙,意思就是不可行,每一次撞墙就切换方向。
- 顺时针螺旋的意思就是方向为:右 下 左 上 右 下 左 上 右 下 左 上 ...
- 由于矩阵的元素个数是有限的,所以我们的循环是有出口的
得分结果: 40.29% 17.78
总结提升:
- 什么是时候需要返回,以免计算重复,这是很重要的问题。
2.2 [59] 螺旋矩阵 Ⅱ
给你一个正整数 n ,生成一个包含 1 到 n^2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。
示例 1:
输入:n = 3
输出:[[1,2,3],[8,9,4],[7,6,5]]
示例 2:
输入:n = 1
输出:[[1]]
提示:
1 <= n <= 20
尝试完成:
/**
* @param {number} n
* @return {number[][]}
*/
var generateMatrix = function (n) {
const matrix = Array(n)
.fill(0)
.map((v) => Array(n).fill(0));
let i = 0;
let j = -1;
let dir = 1; // 1 2 3 4 右 下 左 上
for (let k = 0; k < n * n; k++) {
const num = k + 1;
if (dir === 1) {
if (
matrix[i] &&
typeof matrix[i][j + 1] !== "undefined" &&
matrix[i][j + 1] === 0
) {
j++;
matrix[i][j] = num;
continue;
} else {
dir = 2;
}
}
if (dir === 2) {
if (
matrix[i + 1] &&
typeof matrix[i + 1][j] !== "undefined" &&
matrix[i + 1][j] === 0
) {
i++;
matrix[i][j] = num;
continue;
} else {
dir = 3;
}
}
if (dir === 3) {
if (
matrix[i] &&
typeof matrix[i][j - 1] !== "undefined" &&
matrix[i][j - 1] === 0
) {
j--;
matrix[i][j] = num;
continue;
} else {
dir = 4;
}
}
if (dir === 4) {
if (
matrix[i - 1] &&
typeof matrix[i - 1][j] !== "undefined" &&
matrix[i - 1][j] === 0
) {
i--;
matrix[i][j] = num;
continue;
} else {
dir = 1;
}
}
if (dir === 1) {
if (
matrix[i] &&
typeof matrix[i][j + 1] !== "undefined" &&
matrix[i][j + 1] === 0
) {
j++;
matrix[i][j] = num;
continue;
} else {
dir = 2;
}
}
}
return matrix;
};
我的思路:
- 首先初始化矩阵所有元素值都等于 0,与矩阵外的索引 undefined 拉开差距
- 然后循环 n^2 次,每次确定正确的位置,填上序列号 + 1
- 方向仍然为 右 下 左 上的循环顺序
得分结果: 99.36% 29.77%
总结提升:
- 在 js 中初始化一个全 0 矩阵的方式为:
const matrix = Array(n).fill(0).map(v => Array(n).fill(0))其它方法很容易出错。 - 老生常谈的问题了
if(0)
3. 三个前端题目
- 叙述
+操作符的计算规则
- bigint 不能出现在一般的+运算中!
- 所有值作为+的操作数的时候都会先转成 number 或者 string 类型之后再使用转换值计算
- symbol 不能向 number 或者 string 隐式转换,所以 symbol 也不能参与+运算
- 如果操作数之一为 string 类型的,或者转化类型之后为 string 的,则应该按照【与字符串做加法隐式转换规则】计算
- 如果操作数之一为 number 类型的,并且另一个操作数不为 string 或者转化类型之后的 string,则应该按照【与数字做加法隐式转换规则】计算
- 如果两个操作数均不为 number 或者 string,或者转换之后的类型军部为 number 或者 string,则只有可能是 null undefined boolean,它们都是先转成 number 类型的再计算
- 引用类型转成 number 或者 string 的方式为,依次检查: valueOf -> toString -> Object.prototype.toString.call(x)的返回值。
bigint类型的作用 由于 js 遵循的是 IEEE 双精度浮点数标准,也就是使用 64bit 的二进制数去表示一个浮点数,其中 1bit 为符号位,11bit 为指数位,剩下的 52 位为尾数。
这就造成了 52bit 最大只能表示绝对值为2^53 - 1的数字,如果将符号位算进来,就是-(2^53 - 1) -> +(2^53 - 1),也就是-2^53+1 -> 2^53-1。
这恰好对应了Number.MAX_SAFE_INTEGER和Number.MIN_SAFE_INTEGER的值。
也就是说超过这个范围,js 就只能用浮点数代替了,就会产生舍入误差了。所以ECMAScript 2020才引入bigint这个新的数据类型来表示这个范围之外的整数。
bigint 的原理就是使用非固定长度的二进制数表示整数,因为其长度是不固定的,所以 bigint 的数据不能参与到和 number 类型的数据的运算过程中去。 3. 对比扩展运算符和 Object.assign
- 相同点:
- 两者都是浅拷贝
- 在实现浅拷贝功能的时候,两者都是后面的值覆盖前面的值
- 都只会复制 ownProperty,包括 ownPropertyName 和 ownPropertySymbol,不涉及原型链上的属性
- 不同点:
- 浅拷贝只是扩展运算符的众多用途的一种
- 扩展运算符产生一个新的对象,而 Object.assign 是往目标对象上合并属性(不会产生新的对象)
- 此外:{...obj1, ...obj2}相当于 Object.assign({}, obj1, obj2)
4. 6 个常见邮件错误
- I would like to remember everyone that registration for the conference ends on Thursday this week.
- remember -> remind (remind means to let someone else to remember)
- Could you please remind Mr Singh about the product catalogues?
- We can assure you that you will receive the goods util 2 pm on Firday.
- util -> by (util tells how long the situation continues, but by means the time something happens before that)
- We need to have the report finished by 12 pm on Monday.
- I'm afraid but Mr Johnson will not be able to attend the meeting tomorrow.
- but -> X (I'm afraid + subject/that)
- I'm afraid we won't have time to discuss that topic tomorrow.
- In out next meeting, we will discuss about the new marketing strategy.
- about -> X (not talk about, never use about after discuss) (have a discussion on/about something)
- I think we should discuss these problems in our weekly meeting.
- Would you mind to send me the results of the survey again? I think I deleted the original email
by mistake.
- send to -> sending (mind doing something)
- Would you mind confirming the details once again?
- I would like to inform that we have
accepted your proposal, and would you like toarrange another meetingtodiscuss the next steps.
- inform -> inform you (inform sb sth)
- We would like to inform you that this year's conference will take place in Chennai.