常见的代码问题
... 2022-12-23 About 2 min
# 常见的代码问题
# 写一个mySetInterVal(fn, a, b),每次间隔 a,a+b,a+2b,...,a+nb 的时间,执行一次fn,然后写一个 myClear,停止上面的 mySetInterVal
查看演示代码
class mySetTnterval{
constructor (fn, a, b){
this.a = a
this.b = b
this.fn = fn
this.timer = null
this.count = 0
}
start () {
this.fn()
this.timer = setTimeout(() => {
this.count++
this.start()
console.log(this.a + this.count * this.b)
}, this.a + this.count * this.b);
}
stop () {
clearTimeout(this.timer)
this.count = 0
}
}
const demo = new mySetTnterval(() => console.log(111), 1000, 2000)
demo.start()
demo.stop()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 实现 add(1)(2)(3)
/**
* add(1)(2)(3)
*/
const add = function() {
if(!add.result) add.result = 0
add.result = [...arguments].reduce((sum,item) => sum + item, add.result)
return add
}
const s = add(1, 2)(3)(4,5).result
console.log(s)
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
# 如何实现Promise
查看演示代码
const STATUS = {
PENDDING: 'pendding',
FULFILLED: 'fulfilled',
REJECTED: 'rejected'
}
class myPromise {
constructor(rightnow) {
this.status = STATUS.PENDDING
this.value = undefined
this.reason = undefined
this.onRejectedCBs = []
this.onResolvedCBs = []
const resolve = value => {
if (this.status = STATUS.PENDDING) {
this.status = STATUS.FULFILLED
this.value = value
this.onResolvedCBs.forEach(fn => fn())
}
}
const reject = reason => {
if (this.status = STATUS.PENDDING) {
this.status = STATUS.REJECTED
this.reason = reason
this.onRejectedCBs.forEach(fn => fn())
}
}
try {
rightnow(resolve, reject)
} catch (error) {
throw error
}
}
then(onResolved, onRejected) {
const re_promise = new myPromise((resolve, reject) => {
const actions = {
[STATUS.FULFILLED]: () => {
const x = onResolved(this.value)
/**
* resolvePromise需要满足如下含义
* 1. 如果x为re_promise本身直接跳reject,否则无限循环
* 2. 如果x不为promise,直接将x的值resolve到下一个then中去
* 3. 如果x位reject,直接返回reject到下一个catch中去
*/
resolvePromise(re_promise, x, resolve, reject)
},
[STATUS.REJECTED]: () => {
const x = onRejected(this.reason)
resolvePromise(re_promise, x, resolve, reject)
},
[STATUS.PENDDING]: () => {
this.onRejectedCBs.push(() => {
const x = onRejected(this.reason)
resolvePromise(re_promise, x, resolve, reject)
})
this.onResolvedCBs.push(() => {
const x = onResolved(this.value)
resolvePromise(re_promise, x, resolve, reject)
})
}
}
actions[this.status]?.()
})
return re_promise
}
catch(onRejected) {
this.then(null, onRejected)
}
}
/**
*
* @param {Promise} promise 返回的promise
* @param {any} x 前一个then的return值
* @param {function} resolve promise的resolve
* @param {function} reject promise的reject
* @returns Promise
*/
const resolvePromise = (promise, x, resolve, reject) => {
if (promise === x) {
return reject(new Error('then中的方法返回的promise和构造函数一样,会无限循环'))
}
let caller = false
if (isPromiseLike(x)) {
try {
const then = x.then
then.call(x, (y) => {
if (caller) return
caller = true
resolvePromise(promise, y, resolve, reject)
}, err => {
if (caller) return
caller = true
reject(err)
})
} catch (error) {
if (caller) return
caller = true
reject(error)
}
} else {
resolve(x)
}
}
// note: Promise A+ 规范: https://promisesaplus.com/
const isPromiseLike = p => p !== null && (typeof p === 'object' || typeof p === 'function') && typeof p.then === 'function'
new myPromise((resolve, reject) => {
setTimeout(() => {
resolve('resolve')
}, 1000)
setTimeout(() => {
reject('reject')
}, 3000)
}).then((res => {
console.log('res------>', res)
}), (err) => {
console.log('err------>', err)
})
// note: promise
if(!Promise.all) {
Promise.prototype.all = function(promises) {
return new Promise((resolve, reject) => {
let result = []
let count = 0
let fulfillCount
for (const item of promises) {
const index = count
count++
Promise.resolve(item).then(res => {
result[index] = res
fulfillCount++
if(fulfillCount === count) {
resolve(result)
}
}, reject)
}
})
}
}
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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# 手写数组转树
查看演示代码
let input = [
{
id: 1,
val: "学校",
parentId: null,
},
{
id: 2,
val: "班级1",
parentId: 1,
},
{
id: 3,
val: "班级2",
parentId: 1,
},
{
id: 4,
val: "学生1",
parentId: 2,
},
{
id: 5,
val: "学生2",
parentId: 3,
},
{
id: 6,
val: "学生3",
parentId: 3,
},
];
const buildTree = (arr, parentId, childrenArray) => {
arr.forEach(item => {
if (item.parentId === parentId) {
item.children = []
buildTree(arr, item.id, item.children)
childrenArray.push(item)
}
})
}
const arrayToTree = (arr, parentId) => {
const array = []
buildTree(arr, parentId, array)
return array.length ? (array.length === 1 ? array[0] : array) : {}
}
const obj = arrayToTree(input, null)
console.info(JSON.stringify(obj))
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
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
# 随便打开一个网页,用 JavaScript 打印所有以 s 和 h 开头的标签,并计算出标签的种类
const allTags = [...document.querySelectorAll('*')].reduce((arr, item) => {
if (!arr.includes(item.localName)){
arr.push(item.localName)
}
return arr
}, [])
console.log('所有品类------->', allTags.length)
console.log('s/h标签名------->', allTags.filter(item => item[0] === 's' || item[0] === 'h'))
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# 1000*1000 的画布,上面有飞机、子弹,如何划分区域能够更有效的做碰撞检测,类似划分区域大小与碰撞检测效率的算法,说一下大致的思路
查看演示代码
/**
* 思路:二维的碰撞检测其实就是两个一维数组的相交,定好相关的标准就可以
* 1. 已左上角为笛卡尔坐标系的(0,0)点
* 2. 用三个要素(左上角坐标、宽、高)来一个长方形(物体)的唯一位置
* 3. 这样就变成了同一平面两个长方形的碰撞检测了
*/
// NOTE: 检测某一个点是否在矩形中
const checkPointInRect = (point = {x: 0, y: 0}, rect = {p: {x: 0, y: 0}, w: 10, h: 20}) => {
return point.x >= rect.p.x && point.x <= rect.p.x + rect.w && point.y >= rect.p.y && point.y <= rect.p.y + rect.h
}
const checking = (rectA = { p: {x: 0, y: 0}, w: 10, h: 20 }, rectB = { p: {x: 0, y: 0}, w: 10, h: 20 }) => {
// NOTE: 其中一个矩形中的任何一个顶点在另一个矩形中,则表示他们肯定是相交(碰撞)的
const lefttop = rectA.p
const righttop = {x: rectA.p.x + rectA.w, y: rectA.p.y}
const leftbottom = {x: rectA.p.x, y: rectA.p.y + rectA.h}
const rightbottom = {x: rectA.p.x + rectA.w, y: rectA.p.y + rectA.h}
return checkPointInRect(lefttop, rectB) || checkPointInRect(righttop, rectB) || checkPointInRect(leftbottom, rectB) || checkPointInRect(rightbottom, rectB)
}
const rA = {
p: { x: 0, y: 0 },
w: 10,
h: 20
}
const rB = {
p: { x: 10, y: 10 },
w: 10,
h: 20
}
console.log(checking(rA, rB))
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
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
扩展:在三维里面两个物体的碰撞,其实和上面的作法是一样,就不写了
延展思维:两个矩阵点乘
查看演示代码
/**
* ?:两个矩阵点乘的问题
* 1. 判断是否为矩阵形式
* 2. 判断是否可以相乘
* 3. 计算出最后的结果
*/
let arr = [
[1, 2, 3],
[2, 3, 4],
[3, 4, 5],
[4, 5, 6],
];
let arr1 = [
[1, 2],
[2, 3],
[3, 4],
];
// 判断是否为矩阵形式的二维数组
let isMatrix = (arr) =>
Array.isArray(arr) &&
arr.length > 0 &&
arr.every((item) => Array.isArray(item) && item.length === arr[0].length);
let matrixMulti = (matrix, matrix1) => {
// 先判断是否满足矩阵相乘的条件
// 1. 确保两个数组都是矩阵数组
if (!isMatrix(matrix) || !isMatrix(matrix1)) return "存在不为矩阵的数组";
// 2. 矩阵函数列数是可以相乘的
if (matrix1.length !== matrix[0].length)
return `${matrix.length}*${matrix[0].length}和${matrix1.length}*${matrix1[0].length}的矩阵不可点乘`;
// 先确定矩阵的行数和列数
const [row, col] = [matrix.length, matrix1[0].length];
let result = [];
for (let i = 0; i < row; i++) {
let arr = []; // 数组有几行
for (let j = 0; j < col; j++) {
// 一行中的每个数对应的值
arr.push(
matrix[i].reduce(
(sum, item, index) => sum + item * matrix1[index][j],
0
)
);
}
result.push(arr);
}
return result;
};
console.log("---------->", matrixMulti(arr, arr1));
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
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
# 给定一个数组,按找到每个元素右侧第一个比它大的数字,没有的话返回-1 规则返回一个数组
/*
* 示例:
* 给定数组:[2,6,3,8,10,9]
* 返回数组:[6,8,8,10,-1,-1]
*/
const func = arr => arr.reduce((newArr, item, index) => {
newArr[index] = arr.slice(index).filter(f => f > item)?.[0] || -1
return newArr
}, [])
console.log(func([2,6,3,8,10,9]))
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
# 类设计:使用面相对象设计一个停车场管理系
查看演示代码
/*
* 题目要求
* 使用面相对象设计一个停车场管理系统,该停车场包含:
* 1.停车位,用于停放车辆;
* 2.停车位提示牌,用于展示剩余停车位;
* 可以丰富该系统的元素,给出类,类属性,类接口。
*/
const AllCarapaceNum = 500
class ParkCar {
constructor () {
this.rest = AllCarapaceNum
}
comeinCarapace (num = 1) {
if (this.rest > num) {
this.rest -=num
} else {
console.log('车位不够了,请等待')
}
}
comeoutCarapace (num = 1) {
this.rest ++
}
restCarapaceNum () {
console.log(this.rest)
}
}
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
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
# 手写代码实现kuai-shou-front-end=>KuaiShouFrontEnd
const str = 'kuai-shou-front-end'
// NOTE: 横线转驼峰
const lineToW = str => str.replace(/(-\w)/g, $1 => $1[1].toUpperCase())
// NOTE: 驼峰转横线
const wToLine = str => str.replace(/[A-Z]/g, $1 => `-${$1.toLowerCase()}`)
console.log(wToLine(lineToW(str)))
1
2
3
4
5
6
2
3
4
5
6
# 用尽量短的代码实现一个 arrary 的链式操作,将数组中的大于 10 的值进行一个累加
const sum10 = arr => arr.reduce((sum, item) => item <= 10 ? (sum + +item) : sum, 0)
console.log(sum10([1,2,3,4,5,11])) // 15
1
2
2