202306
INFO
6 月了,还不知道路在哪儿? 要做长久打算!
- 20230522
- 0602 不就是写一些伪代码吗 全背下来不就好了
- 0607 已经坚持五天 继续坚持一个月
Details
默写平时可能用到的手写题
- mockNew
- apply/call/bind
- compose
- lru
- 二分法
- curry/curry2
- deepclone
- 无重复的最长子串
- 反转链表
- 删除链表某一个节点
0601
ts 练习 Subsequence
实现 Subsequence<T>
输出所有可能的子序列:
ts
type PP3 = Subsequence<[1, 2]>; // [] | [1] | [2] | [1, 2]
type Subsequence<T> = T extends [infer F, ...infer R extends number[]]
? Subsequence<R> | [F, ...Subsequence<R>]
: T;
type PP4 = Subsequence<[1, 2, 3]>; // [] | [1, 2] | [2] | [1] | [1, 2, 3] | [2, 3] | [3] | [1, 3]
数组全排列 arr = [1,2,3]
js
function permute(arr) {
var res = [];
var len = arr.length;
var backTrack = (arr, temp) => {
res.push(temp.slice());
for (let i = 0; i < len; i++) {
if (!temp.includes(arr[i])) {
temp.push(arr[i]);
dfs(arr, temp);
temp.pop();
}
}
};
backTrack(arr, []);
return res;
}
permute([1, 2, 3]);
0602
- 【代码题】 实现 compose 函数, 类似于 koa 的中间件洋葱模型
js
// 题目需求
let middleware = [];
middleware.push((next) => {
console.log(next, "next");
console.log(1);
next();
console.log(1.1);
});
middleware.push((next) => {
console.log(2);
next();
console.log(2.1);
});
middleware.push((next) => {
console.log(3);
next();
console.log(3.1);
});
function compose(arr) {
return (next) => {
return dispatch(0);
function dispatch(i) {
let fn = arr[i];
if (!fn) return Promise.resolve();
if (i === arr.length) fn = next;
try {
return Promise.resolve(fn(dispatch.bind(null, i + 1)));
} catch (e) {
return Promise.reject(e);
}
}
};
}
let fn = compose(middleware);
fn();
// 1 2 3 3.1 2.1 1.1
举个例子
js
/**
* Your LRUCache object will be instantiated and called as such:
* var obj = new LRUCache(capacity)
* var param_1 = obj.get(key)
* obj.put(key,value)
*/
class LRU {
constrcuor(num) {
this.res = new Map();
this.limit = num;
}
get(key) {
// 如果存在 当前key滞后
// 如果不存在 则返回-1
if (this.res.has(key)) {
var cur = this.res.get(key);
this.res.delete(key);
this.res.set(key, cur);
return cur;
} else {
return -1;
}
}
put(key, value) {
// 如果没有直接设置
var size = this.res.size;
if (this.res.has(key)) {
this.res.delete(key);
} else {
// 如果有的话 看总数
if (this.limit <= size) {
const oldKey = this.res.keys().next().value;
this.res.delete(oldKey);
}
}
this.res.set(key, value);
}
}
TS 练习, PickByType
实现 PickByType<P, Q>
,将对象 P 中类型为 Q 的 key 保留:
ts
type OnlyBoolean = PickByType<
{
name: string;
count: number;
isReadonly: boolean;
isEnable: boolean;
},
boolean
>; // { isReadonly: boolean; isEnable: boolean; }
type PickByType<T extends Record<PropertyKey, any>, K> = {
[U in keyof T as T[U] extends K ? U : never]: T[U];
};
type TT111 = { name: string; age: number };
type PP11 = Pick<TT111, "name">;
type PickTest<T extends Record<PropertyKey, any>, K extends keyof T> = {
[P in K]: T[P];
};
type TT211 = PickTest<TT111, "name">;
- 语录: 杨绛先生说:人在最艰难的时候,别老想着太远的将来,只要鼓励自己过好今天就好,这世界有太多的猝不及防,人生就是一场体验,请你尽兴。 岁月静好是片刻,一地鸡毛是日常,即使世界偶尔薄凉,内心也有繁花似锦,浅浅喜,静静爱,深深懂得,淡淡释怀,不去惊艳谁的人生,只温柔自己的岁月,落落大方,好好生活,望远处是风景,看近处才是人生,惟愿余生,岁月无恙,直言温暖,不语悲伤
0603
- 如果不能继续向前学习,重拾以前也能打败 60%的,那就好好重拾以前!
- 练习 Ts PartialByKeys
实现 PartialByKeys<T, K>
,使 K 匹配的 Key 变成可选的定义,如果不传 K 效果与 Partial 一样:
ts
interface User {
name: string;
age: number;
address: string;
}
type TT3 = Partial<User>;
type UserPartialName = PartialByKeys<User, "name">; // { name?:string; age:number; address:string }
type PartialByKeys<T, K = keyof T> = {
[P in keyof T as P extends K ? P : never]?: T[P];
} & {
[P in keyof T as P extends K ? never : P]: T[P];
} extends infer R
? {
[P in keyof R]: R[P];
}
: never;
type HasIn<Arr, One> = Arr extends [infer F, ...infer R]
? Equal<One, F> extends true
? true
: HasIn<R, One>
: false;
type TT4 = HasIn<[1, 2, 3], 1>;
type Equal<A, B> = (<T>() => T extends A ? 1 : 2) extends <T>() => T extends B
? 1
: 2
? true
: false;
type TT5 = Equal<1, any>;
默写 compose
js
function compose(arr) {
return (ctx, next) => {
return dispatch(0);
function dispatch(i) {
var fn = arr[i];
if (!fn) return Promise.resolve();
if (i === arr.length) fn = next;
try {
return Promise.resolve(fn(ctx, () => dispatch(i + 1)));
} catch (e) {
return Promise.reject(e);
}
}
};
}
默写 LRU
get/set
js
class LRU {
constructor(num) {
this.cache = new Map();
this.limit = num;
}
get(key) {
if (this.cache.has(key)) {
const val = this.cache.get(key);
this.cache.delete(key);
this.cache.set(key, val);
return val;
}
return -1;
}
set(key, val) {
if (this.cache.has(key)) {
this.cache.delete(key);
} else {
// 需要删除头部的key
// 删除的前提是池子满了
if (this.limit <= this.cache.size) {
var oldKey = this.cache.keys().next().value;
this.cache.delete(oldKey);
}
}
this.cache.set(key, val);
}
}
默写反转链表
js
function reverse(head) {
let cur = head;
let pre = null;
while (cur) {
var next = cur.next;
cur.next = pre;
pre = cur;
cur = next;
}
return pre;
}
0604
做饭做了四个小时,
0605
访问页面 -> nginx -> 网关 -> 微服务
请求:Browser -> nginx -> 网关 -> node -> webqiji 返回: webqiji(Data) -> node(HTML) -> 网关 -> nginx -> Browser
- ts 练习 1 实现函数 PromiseAll,输入 PromiseLike,输出
Promise<T>
,其中 T 是输入的解析结果:
ts
const promiseAllTest1 = PromiseAll([1, 2, 3] as const);
const promiseAllTest2 = PromiseAll([1, 2, Promise.resolve(3)] as const);
const promiseAllTest3 = PromiseAll([1, 2, Promise.resolve(3)]);
declare function PromiseAll<T>(values: T): Promise<{
[K in keyof T]: T[K] extends Promise<infer U> ? U : T[K];
}>;
- ts 练习 2 Type Lookup 实现
LookUp<T, P>
,从联合类型 T 中查找 type 为 P 的项并返回: LookUp<T, P>
ts
interface Cat {
type: "cat";
breeds: "Abyssinian" | "Shorthair" | "Curl" | "Bengal";
}
interface Dog {
type: "dog";
breeds: "Hound" | "Brittany" | "Bulldog" | "Boxer";
color: "brown" | "white" | "black";
}
type MyDog = LookUp<Cat | Dog, "dog">; // expected to be `Dog`
type LookUp<T, P> = T extends {
type: infer U;
}
? U extends P
? T
: never
: never;
type LookUp2<U extends { type: any }, T extends U["type"]> = U extends {
type: T;
}
? U
: never;
type MyDog2 = LookUp2<Cat | Dog, "dog">;
- 手写 js 基础 - new 手写
js
function Person(name) {
this.name = name;
}
function mockNew(fn, ...rest) {
// 创建一个对象
// 新对象的原型属性proto指向构造函数的 prototype 属性
// 执行该方法
// 如果是对象则返回 如果不是对象则需要返回一个对象
var target = Object.create(fn.prototype);
var res = fn.apply(target, rest);
return res instanceof Object ? res : target;
}
var tt1 = new Person("cpp");
var tt2 = mockNew(Person, "cpp");
- 手写 apply 和 call
js
function sayName(name) {
console.log(name, 'fn inner')
return name
}
sayName.call(null, 'wmh')
function mockApply(obj, ...rest) {
obj = Object(obj); || window
var symbol = Symbol()
obj[symbol] = this
var res = obj[symbol](...rest)
delete obj[symbol]
return res
}
手写无重复的最长子串
js
/**
* @param {string} s
* @return {number}
*/
var lengthOfLongestSubstring = function (s) {
if (!s || s.length === 0) return 0;
let max = 0;
let temp = [];
for (let i = 0; i < s.length; i++) {
var index = s.indexOf(s[i]);
if (index > -1) {
arr.splice(0, i + 1);
}
arr.push(s[i]);
max = Math.max(max, arr.length);
}
return max;
};
0606
- 函数柯里化
js
// 参数固定
function curry(fn) {
var judge = (...arg) => {
if (fn.length === arg.length) {
return fn(...arg);
}
return (...args) => judge(...args, ...arg);
};
return judge;
}
var sum = (a, b, c) => a + b + c;
var map = curry(sum);
map(1)(2)(3);
// 参数不固定
function curry2(fn) {
var arr = [];
return function temp(...arg) {
if (arg.length) {
arr.push(...arg);
return temp;
} else {
var res = fn.apply(this, arr);
arr = [];
return res;
}
};
}
var sum1 = (...rest) => rest.reduce((a, b) => a + b, 0);
var map1 = curry2(sum1);
map1(1)(2)(3)();
- 练习 TS-Trim
实现 Trim<T>
,将字符串左侧或者右侧空格清空:
ts
type trimed = TrimLeft<" Hello World ">; // expected to be 'Hello World
type TrimLeft<T extends string> = T extends `${infer A} ` ? TrimLeft<A> : T;
type TR1 = TrimLeft<" cpp ">;
type Trim<T extends string> = T extends `${infer A} ` | ` ${infer A}`
? Trim<A>
: T;
type TR2 = Trim<" cpp ">;
- 练习 TS Capitalize 实现
Capitalize<T>
将字符串第一个字母大写:
ts
type capitalized = Capitalize1<"hello world">; // expected to be 'Hello world'
type Capitalize1<T extends string> = T extends `${infer F}${infer Z}`
? `${Uppercase<F>}${Z}`
: T;
type TR3 = Capitalize<"hello world">;
- 除了勤加练习基本功,还需要熟知常用的八股文,简历上写的 react/vite/rollup
0607
- 2023 年高考第一天,13 年前我参加 2010 年高考,现在回想如果能回去,中考就要好好考,考到县中,大环境很重要,即使在县中倒数也比现在的学校强,其次就是选科,选物化生,理科满级
- 看了年轻人得了癌症的帖子,今日健康来之不易,平时生活习惯很重要,要懂得珍惜
- 手写 bind
js
Function.prototype.myBind = function (context) {
var self = this;
var arg = Array.prototype.slice.call(arguments, 1);
var Bridge = function () {};
var fBind = () => {
var args = Array.from(arguments);
self.apply(this instanceof self ? this : context, [...args, ...arg]);
};
Bridge.prototype = this.prototype;
fBind.prototype = new Brideg();
return fBind;
};
function myName(name, age) {
return "cpp";
}
var obj = {
val: 1,
};
var test1 = myName.bind(obj, "wmh");
test1(30);
- 根据节点值删除该节点
js
/**
* @param {ListNode} head
* @param {number} val
* @return {ListNode}
*/
var deleteNode = function (head, val) {
let dummy = {
val: 0,
next: head,
};
let cur = dummy;
while (cur.next) {
if (cur.next.val === val) {
cur.next = cur.next.next;
break;
}
cur = cur.next;
}
return dummy.next;
};
var test = {
val: 1,
next: {
val: 2,
next: {
val: 3,
next: {
val: 4,
next: {
val: 5,
next: undefined,
},
},
},
},
};
deleteNode(test, 3);
- 链表中是否有环
js
// 快慢指针
/**
* @param {ListNode} head
* @return {boolean}
*/
var hasCycle = function (head) {
var slow = head;
var fase = head;
while (fast && fast.next) {
slow = slow.next;
fast = fast.next.next;
if (slow === fast) {
return true;
}
}
return false;
};
// hash表
var hasCycle = function (head) {
var m = new Map();
while (head) {
if (m.has(head)) {
return true;
}
m.set(head, true);
head = head.next();
}
return false;
};
- 找出链表中环的入口节点
js
/**
* @param {ListNode} head
* @return {ListNode}
* 哈希表存遍历过的节点,每遍历一个节点,都查看哈希表是否存在当前节点,如果存在,则说明链表有环
如果不存在,则存入哈希表,继续遍历
时间复杂度为 O(n),空间复杂度为 O(n)
*/
var detectCycle = function (head) {
var m = new Map();
var cur = head;
while (cur) {
if (m.has(cur)) {
return cur;
}
m.set(cur, cur);
cur = cur.next;
}
return null;
};
0608
如何私有 sourcemap 服务?
按照现在的水平,退休金不会超过 2000 块,如果想达到 3000 块,还能得继续缴 12 年, 得保持现在到 2035 年
今天刷 maimai,看到一条说说
不断操练手写题,没啥意义,唯一的意义就是下次在背书的时候,拾起的速度越来越快,越来越快!!
继续默写手写 js 基础题
js
// 何以解忧 唯有手写代码
// 大数相加
function stringAdd(a, b) {
var len = Math.max(a.length, b.length);
a = a.padStart(len, 0);
b = b.padStart(len, 0);
let res = "";
let flag = 0;
for (let i = len - 1; i >= 0; i--) {
flag = Number(a[i]) + Number(b[i]) + flag;
res = (flag % 10) + res;
flag = Math.floor(flag / 10);
}
res = flag === 1 ? "1" + res : res;
return res;
}
stringAdd("1234", "78901");
- 练习 ts 手写
ts
type Fn = (a: number, b: string) => number;
type Result = AppendArgument<Fn, boolean>;
// expected be (a: number, b: string, x: boolean) => number
type AppendArgument<F, E> = F extends (...arg: infer T) => infer R
? (...arg: [...T, E]) => R
: F;
- 实现 TS 版函数 Replace<S, From, To>,将字符串 From 替换为 To:
ts
type replaced = Replace<"types are fun!", "fun", "awesome">; // expected to be 'types are awesome!'
type Replace<S, F, T extends string> = S extends `${infer FF}${F}${infer R}`
? `${FF}${T}${R}`
: S;
- 实现基本的
ReturnType
ts
function sayName2(value: number, age: number): number;
function sayName2(value: string): string | undefined;
function sayName2(
value: string | number,
age: number = 0
): string | number | undefined {
if (typeof value === "number") {
return age;
} else {
return value;
}
}
// sayName2("1111"); // ok
// sayName2(10, 10); // ok
type TPP1 = ReturnType<typeof sayName2>;
type MockReturnType<T extends (...arg: any) => any> = T extends (
arg: any
) => infer R
? R
: never;
type TPP2 = MockReturnType<typeof sayName2>;
- 实现基本的
Parameters
ts
type TP2 = Parameters<typeof sayName2>;
type MockParamters<T extends (...arg: any) => any> = T extends (
...arg: infer P
) => any
? P
: never;
type TP3 = MockParamters<typeof sayName2>;
0609
- js 手写
js
// 16进制跟rgb进行转换
// #fffff => rgb(255, 255, 255)
function hexToRgb(str) {
var r, g, b;
var rgb = str.replace("#", "0x");
r = rgb >> 16;
g = (rgb >> 8) & 0xff;
b = rgb & 0xff;
return `rgb(${r}, ${g}, ${b})`;
}
// rgb转十六进制
// rgb(255, 255, 255) => #ffffff
function rgbToHex(str) {
const [a, r, g, b] = str.split(/[^\d]+/);
const toHex = (num) => {
const hex = (+num).toString(16);
return hex.length === 1 ? `0${hex}` : hex;
};
return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
}
rgbToHex("rgb(255,255,255)");
0610
- 手写 js 函数名连接符大小写
js
// cpp_wmh => cppWmh
function toRewrite(str) {}
- 手写 js 中的模拟 map/filter/reduce
js
Array.prototype.myMap = function (fn, context) {
var arr = Array.prototype.call(this) || [];
var res = [];
for (let i = 0; i < arr.length; i++) {
res.push(fn.call(context, arr[i], i, arr));
}
return res;
};
var res = [1, 2, 3];
res.map((e) => e * 2);
res.myMap((e) => e * 2);
js
Array.prototype.myReduce = function (fn, init) {};
0611-0614
写业务
0615-0618
苏州拍婚纱
0619
- 手写 reduce
js
Array.prototype.myReduce = function (fn, init) {
const arr = Array.prototype.slice.call(this) || [];
let res = init ? init : arr[0];
for (let i = init ? 0 : 1; i < arr.length; i++) {
res = fn.call(null, res, arr[i], i, arr);
}
return res;
};
var test = [12, 23, 45];
var test2 = test.reduce((a, b) => a + b, 10);
console.log(test2);
- 手写原生 ajax
js
function dealAjax(fn, url) {}
- 打乱数组
js
const shuffle = (arr) => {
return arr.sort((e) => {
return Math.random() > 0.5 ? 1 : -1;
});
};
shuffle([2, 33, 11, 2222, 9]);
- 管道函数
js
function fn1(x) {
console.log(11);
return x + 1;
}
function fn2(x) {
return x + 2;
}
function fn3(x) {
return x + 3;
}
function fn4(x) {
console.log(44);
return x + 4;
}
// 从右往左
const compose = (...fns) => {
if (fns.length === 0) return (num) => num;
if (fns.length === 1) return fns[0];
return fns.reduce((pre, next) => {
return (...num) => {
return pre(next(...num));
};
});
};
var all = compose(fn1, fn2, fn3, fn4);
all(10);
// 从左往右
const pipe = function () {
// 从左往右执行函数组合
const args = [].slice.apply(arguments);
return function (value) {
return args.reduce((acc, fn) => fn(acc), value);
};
};
var double = (x) => x * 2;
var triple = (x) => x * 3;
var quadruple = (x) => x * 4;
var fn = pipe1(double, triple, quadruple);
var fn1 = pipe(double, triple, quadruple);
fn1(2);
0620
- 随时都有被时代淘汰的可能,随时要做好准备
- 继续操练手写 js
js
// 发布订阅模式
class EventEmitter {}
// 数组扁平化
function flatten(arr) {
var stack = [...arr];
var res = [];
while (stack.length) {
var cur = stack.pop();
if (Array.isArray(cur)) {
stack.push(...cur);
} else {
res.push(cur);
}
}
return res.reverse();
}
var test = [
[1, 2, 3],
[2, [3, 4, 5]],
];
console.log(flatten(test));
Array.prototype.myFlat = function (num) {};
0621
- 业务上兼容 IE 浏览器,蛋疼
- 明天回家,准备下
0622/23/24
连云港老家过端午 尽管很想呆在老家,考虑到现实情况,很难
0625
- 继续搬砖
- 大学专业研究下,切记一定是建议,建议,建议,仅供参考,仅供参考,仅供参考,毕竟不是自己去学,也不要替人做决定
- 7 月 1 号去体检,所以最近几天不能超过 12 点睡觉
0626/0627
- 业务上修改 bug
0628
- 找到自己的热爱,这个问题很复杂,不见得一下就有答案,如果还没有找到,请不要放弃
- 什么事都要留有余地,尤其当今,不要亮出自己底牌
- 对方家里的事一概不要提
- 默写 mockReduce
js
Array.prototype.myReduce = function (fn, init) {
const arr = Array.prototype.slice.call(this) || [];
let res = init ? init : arr[0];
for (let i = init ? 0 : 1; i < arr.length; i++) {
res = fn.call(null, res, arr[i], i, arr);
}
return res;
};
0629
- 计算数组中每个元素出现的次数
js
function countEvery(arr) {
let max = 0;
const obj = arr.reduce((acc, cur) => {
if (!(cur in acc)) {
acc[cur] = 1;
} else {
acc[cur] += 1;
max = Math.max(max, acc[cur]);
}
return acc;
}, {});
return max;
}
var arr = ["cpp", "wmh", "cpp", "chen", "chen", "chen"];
var test = countEvery(arr);
console.log(test);
0630
- 来公司的第 750 天,走过了三分之一,还有三分之二的历程
- 又是彷徨的一天,希望自己能振作起来。又到一年一度的复职的日子,回首半年,不知道核心在哪里