手写JS代码收集
# 各种手写 JS 代码
# 通用柯里化函数
const carry = (fn, ...args) => {
return (..._args) => {
_args.unshift(...args)
return _args.length < fn.length ? carry(fn, ..._args) : fn(..._args)
}
}
const add = carry(function (a, b, c, d) {
return a + b + c + d
})
console.log(add(1)(2, 3)(4))
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
# call
Function.prototype.fakeCall = function (ctx = globalThis, ...args) {
const key = Symbol('key')
ctx[key] = this
const res = ctx[key](...args)
delete ctx[key]
return res
}
1
2
3
4
5
6
7
2
3
4
5
6
7
# apply
Function.prototype.fakeApply = function (ctx = globalThis, args) {
const key = Symbol('key')
ctx[key] = this
const res = ctx[key](...args)
delete ctx[key]
return res
}
1
2
3
4
5
6
7
2
3
4
5
6
7
# bind
Function.prototype.fakeBind = function (ctx, ...args) {
return (...rest) => this.call(ctx, ...args, ...rest)
}
1
2
3
2
3
# sleep/delay 函数
function delay(func, seconds, ...args) {
return new Promise((resolve, reject) => {
setTimeout(() => {
Promise.resolve(fun(...args)).then(resolve)
}, seconds)
})
}
1
2
3
4
5
6
7
2
3
4
5
6
7
# 数组扁平化的函数 flatten
function flatten(list, depth = 1) {
if (depth === 0) return list
return list.reduce(
(a, b) => a.concat(Array.isArray(b) ? flatten(b, depth - 1) : b),
[]
)
}
1
2
3
4
5
6
7
2
3
4
5
6
7
# String.prototype.trim
const trim = str => str.trim || str.replace(/^\s+|\s+$/g, '')
1
# 防抖
// 防抖函数
function debounce(fn, wait) {
let timer
return function () {
let _this = this
let args = arguments
if (timer) {
clearTimeout(timer)
}
timer = setTimeout(function () {
fn.apply(_this, args)
}, wait)
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
# 节流
// 方式1: 使用时间戳
function throttle1(fn, wait) {
let time = 0
return function () {
let _this = this
let args = arguments
let now = Date.now()
if (now - time > wait) {
fn.apply(_this, args)
time = now
}
}
}
// 方式2: 使用定时器
function thorttle2(fn, wait) {
let timer
return function () {
let _this = this
let args = arguments
if (!timer) {
timer = setTimeout(function () {
timer = null
fn.apply(_this, args)
}, wait)
}
}
}
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
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
# LRU 缓存算法
class LRUCache {
constructor(capacity = 10) {
this.map = new Map()
this.capacity = capacity
}
get(key) {
if (!this.map.has(key)) return -1
const value = this.map.get(key)
this.map.delete(key)
this.map.set(key, value)
return value
}
put(key, value) {
if (this.map.has(key)) {
this.map.delete(key)
}
this.map.set(key, value)
while (this.map.size > this.capacity) {
this.map.delete(this.map.keys().next().value)
}
}
}
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
# 列表转树
function listToTree(data) {
const temp = {}
const treeData = []
for (let i = 0; i < data.length; i++) {
temp[data[i].id] = data[i]
}
for (let i in temp) {
if (+temp[i].parentId != 0) {
if (!temp[temp[i].parentId].children) {
temp[temp[i].parentId].children = []
}
temp[temp[i].parentId].children.push(temp[i])
} else {
treeData.push(temp[i])
}
}
return treeData
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 树转列表
function treeToList(data) {
let res = []
const dfs = tree => {
tree.forEach(item => {
if (item.children) {
dfs(item.children)
delete item.children
}
res.push(item)
})
}
dfs(data)
return res
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
# ajax
const ajax = ({ url, method, body, headers }) => {
return new Promise((resolve, reject) => {
const request = new XMLHttpRequest()
request.open(method, url)
for (const key in headers) {
request.setRequestHeader(key, headers[key])
}
request.onreadystatechange = () => {
if (request.readyState === 4) {
if (request.status >= 200 && request.status < 300) {
resolve(request.responseText)
} else if (request.status >= 400) {
reject(request)
}
}
}
request.send(body)
})
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# Promise.all
function fakePromiseAll(_promises) {
return new Promise((resolve, reject) => {
// Iterable => Array
const promises = Array.from(_promises)
// 结果用一个数组维护
const r = []
const len = promises.length
let count = 0
for (let i = 0; i < len; i++) {
// Promise.resolve 确保把所有数据都转化为 Promise
Promise.resolve(promises[i])
.then(o => {
// 因为 promise 是异步的,保持数组一一对应
r[i] = o
// 如果数组中所有 promise 都完成,则返回结果数组
if (++count === len) {
resolve(r)
}
// 当发生异常时,直接 reject
})
.catch(e => reject(e))
}
})
}
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 深拷贝
function deepClone(target) {
const map = new WeakMap()
function isObject(target) {
return (
(typeof target === 'object' && target) || typeof target === 'function'
)
}
function clone(data) {
if (!isObject(data)) {
return data
}
if ([Date, RegExp].includes(data.constructor)) {
return new data.constructor(data)
}
if (typeof data === 'function') {
return new Function('return ' + data.toString())()
}
const exist = map.get(data)
if (exist) {
return exist
}
if (data instanceof Map) {
const result = new Map()
map.set(data, result)
data.forEach((val, key) => {
if (isObject(val)) {
result.set(key, clone(val))
} else {
result.set(key, val)
}
})
return result
}
if (data instanceof Set) {
const result = new Set()
map.set(data, result)
data.forEach(val => {
if (isObject(val)) {
result.add(clone(val))
} else {
result.add(val)
}
})
return result
}
const keys = Reflect.ownKeys(data)
const allDesc = Object.getOwnPropertyDescriptors(data)
const result = Object.create(Object.getPrototypeOf(data), allDesc)
map.set(data, result)
keys.forEach(key => {
const val = data[key]
if (isObject(val)) {
result[key] = clone(val)
} else {
result[key] = val
}
})
return result
}
return clone(target)
}
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
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
# new
const fakeNew = function (fn, ...args) {
const instance = Object.create(fn.prototype)
const res = fn.call(instance, ...args)
if (res && (typeof res === 'object' || typeof res === 'function')) {
return res
}
return instance
}
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# 继承
function Parent(name) {
this.name = name
this.sing = () => {
console.log('sing')
}
}
Parent.prototype.dance = () => {
console.log('dance')
}
function Children(name, age) {
Parent.call(this, name)
this.age = age
}
Children.prototype.rap = () => {
console.log('rap')
}
Children.prototype = Object.create(Parent.prototype)
Children.prototype.constructor = Children
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# Promise
class fakePromise {
static resolve(value) {
if (value && value.then) {
return value
}
return new fakePromise(resolve => resolve(value))
}
constructor(fn) {
this.value = undefined
this.reason = undefined
this.status = 'PENDING'
// 维护一个 resolve/pending 的函数队列
this.resolveFns = []
this.rejectFns = []
const resolve = value => {
// 注意此处的 setTimeout
setTimeout(() => {
this.status = 'RESOLVED'
this.value = value
this.resolveFns.forEach(({ fn, resolve: res, reject: rej }) =>
res(fn(value))
)
})
}
const reject = e => {
setTimeout(() => {
this.status = 'REJECTED'
this.reason = e
this.rejectFns.forEach(({ fn, resolve: res, reject: rej }) =>
rej(fn(e))
)
})
}
fn(resolve, reject)
}
then(fn) {
if (this.status === 'RESOLVED') {
const result = fn(this.value)
// 需要返回一个 fakePromiseise
// 如果状态为 resolved,直接执行
return fakePromise.resolve(result)
}
if (this.status === 'PENDING') {
// 也是返回一个 fakePromiseise
return new fakePromise((resolve, reject) => {
// 推进队列中,resolved 后统一执行
this.resolveFns.push({ fn, resolve, reject })
})
}
}
catch(fn) {
if (this.status === 'REJECTED') {
const result = fn(this.value)
return fakePromise.resolve(result)
}
if (this.status === 'PENDING') {
return new fakePromise((resolve, reject) => {
this.rejectFns.push({ fn, resolve, 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
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
编辑 (opens new window)
上次更新: 2022/06/30, 23:08:13