手写实现
Alphawq 9/3/2021
- 1. instanceof
- 2. Object.create
- 3. new
- 4. call & apply
- 5. bind
- 6. 柯里化
- 7. 寄生组合继承
- 9. 节流函数
- 10. Promise
- 11. Promise.resolve
- 12. Promise.reject
- 13. Promise.all
- 14. Promise.any
- 15. Promise.allSettled
- 16. Promise.race
- 17. Promise.prototype.catch
- 18. Promise.prototype.finally
- 19. 浅拷贝
- 20. 深拷贝
- 21. 快速排序
- 22. EventBus
- 23. 异步并发控制
- 24. LRU 算法
- 25. promisify
- 26. 简易模板引擎
# 1. instanceof
function myInstanceof(left, right) {
if (typeof left !== object || left === null) return false
let lproto = Object.getPrototypeOf(left)
let rprototype = right.prototype
while (lproto) {
if (lproto === rprototype) return true
lproto = Object.getPrototypeOf(lproto)
}
return false
}
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
# 2. Object.create
function create(obj) {
let _proto = new Object(obj)
function F() {}
F.prototype = _proto
return new F()
}
1
2
3
4
5
6
2
3
4
5
6
# 3. new
function myNew(ctor, ...args) {
if (typeof ctor !== 'function')
throw new TypeError(ctor + 'must be a function')
let proto = Object.create(ctor.prototype)
let res = ctor.apply(proto, args)
if (typeof res === 'object' && res !== null) return res
return proto
}
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# 4. call & apply
Function.prototype.myCall = function (ctx, ...args) {
let self = this
ctx.fn = self
let res = ctx.fn(...args)
delete ctx.fn
return res
}
Function.prototype.apply = function (ctx, ...args) {
let self = this
ctx.fn = self
let res = ctx.fn(args)
delete ctx.fn
return res
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 5. bind
Function.prototype.myBind = function (ctx, ...arg1) {
let fToBind = this
function fBound() {
let _args = [...arg1, ...arguments]
let res = fToBind.apply(this instanceof fToBind ? this : ctx, _args)
return res
}
fBound.prototype = Object.create(fToBind.prototype)
return fBound
}
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
# 6. 柯里化
function curry(fn) {
let _len = fn.length
let _args = []
return function _curry(...args) {
_args = _args.concat(args)
if (_args.length < _len) return _curry
return fn(..._args)
}
}
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# 7. 寄生组合继承
function A() {}
function B() {
A.apply(this, ...arguments)
}
B.prototype = Object.create(A.prototype, {
constructor: {
value: B,
},
})
// 8. 防抖函数
function debounce(fn, wait) {
let timer = null
return function () {
if (timer) {
clearTimeout(timer)
}
timer = setTimeout(() => {
fn.call(this, ...arguments)
timer = null
}, 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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 9. 节流函数
function throttle(fn, wait) {
let last = Date.now()
return function () {
let current = Date.now()
if (current - last < wait) return
now = current
return fn.call(this, ...arguments)
}
}
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# 10. Promise
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class Promise {
constructor(excutor) {
this.state = PENDING
this.value = void 0
this.reason = void 0
this.onFulfilledCbs = []
this.onRejectedCbs = []
let resolve = (value) => {
if (this.state === PENDING) {
this.state = FULFILLED
this.onFulfilledCbs.forEach((fn) => fn(this.value))
}
}
let reject = (reason) => {
if (this.state === PENDING) {
this.state = REJECTED
this.reason = reason
this.onRejectedCbs.forEach((fn) => fn(this.reason))
}
}
try {
excutor(resolve, reject)
} catch (error) {
reject(error)
}
}
then(onFulfilledCb, onRejectedCb) {
onFulfilledCb =
typeof onFulfilledCb === 'function' ? onFulfilledCb : (data) => data
onRejectedCb =
typeof onRejectedCb === 'function'
? onRejectedCb
: (reason) => {
throw reason
}
let p2 = new Promise((resolve, reject) => {
let wrappedFulfilledCb = () => {
queueMicrotask(() => {
try {
onFulfilledCb(this.data)
} catch (error) {
reject(error)
}
})
}
let wrappedRejectedCb = () => {
queueMicrotask(() => {
try {
onRejectedCb(this.reason)
} catch (error) {
reject(error)
}
})
}
if (this.state === FULFILLED) {
wrappedFulfilledCb()
}
if (this.state === REJECTED) {
wrappedRejectedCb()
}
if (this.state === PENDING) {
this.onFulfilledCbs.push(wrappedFulfilledCb)
this.onRejectedCbs.push(wrappedFulfilledCb)
}
})
return p2
}
}
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
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
# 11. Promise.resolve
Promise.resolve = function (value) {
if (value instanceof Promise) return value
return new Promise((resolve, reject) => {
if (value.then && typeof value.then === 'function') {
return value.then(resolve, reject)
}
return resolve(value)
})
}
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# 12. Promise.reject
Promise.reject = function (reason) {
return new Promise((_, reject) => {
reject(reason)
})
}
1
2
3
4
5
2
3
4
5
# 13. Promise.all
Promise.all = function (promises) {
let len = promises.length
let res = []
return new Promise((resolve, reject) => {
if (!Array.isArray(promises))
return reject(new TypeError('must be an array'))
for (let i = 0; i < len; i++) {
promises[i].then(
(value) => {
res[i] = value
if (res.length === len) resolve(res)
},
(reason) => {
reject(reason)
}
)
}
})
}
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
# 14. Promise.any
Promise.any = function (promises) {
let len = (_len = promises.length)
return new Promise((resolve, reject) => {
if (!Array.isArray(promises))
return reject(new TypeError('must be an array'))
for (let i = 0; i < len; i++) {
p[i].then(
(value) => {
return resolve(value)
},
(reason) => {
if (!--_len) return reject(new Error('rejected'))
}
)
}
})
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 15. Promise.allSettled
Promise.allSettled = function (promises) {
let len = promises.length
let res = []
let done = () => {
if (res.length === len) return res
}
return new Promise((resolve, reject) => {
for (let i = 0; i < len; i++) {
p.then(
(value) => {
res[i] = {
state: 'fulfilled',
value,
}
done()
},
(reason) => {
res[i] = {
state: 'rejected',
reason,
}
done()
}
)
}
})
}
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
# 16. Promise.race
Promise.race = function (promises) {
return new Promise((resolve, reject) => {
for (let p of promises) {
p.then(resolve, reject)
}
})
}
1
2
3
4
5
6
7
2
3
4
5
6
7
# 17. Promise.prototype.catch
Promise.prototype.catch = function (fn) {
return this.then(_, fn)
}
1
2
3
2
3
# 18. Promise.prototype.finally
Promise.prototype.finally = function (fn) {
return this.then(
(value) => {
return Promise.resolve(fn()).then(() => {
return value
})
},
(reason) => {
return Promise.resolve(fn()).then(() => {
throw reason
})
}
)
}
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
# 19. 浅拷贝
function shallowClone(target) {
if (typeof target === 'object' && target !== null) {
let clone = Array.isArray(target) ? [] : {}
for (let key in target) {
if (target.hasOwnProperty(key)) {
clone[key] = target[key]
}
}
return clone
}
return target
}
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
# 20. 深拷贝
function deepClone(source, map = new WeakMap()) {
let getType = (target) =>
Object.prototype.toString.call(target).replace(/\[object (\w+)\]/, '$1')
let isComplexType = (target) =>
(typeof target === 'object' || typeof target === 'function') &&
target !== null
if (getType(source) === 'Date') return new Date(source)
if (getType(source) === 'RegExp') return new RegExp(source)
let allDesc = Object.getOwnPropertyDescriptors(source)
let clone = Object.create(Object.getPrototypeOf(source), allDesc)
if (map.has(source)) {
return map.get(source)
}
map.set(source, clone)
for (let key of Reflect.ownKeys(source)) {
clone[key] = isComplexType(source[key])
? deepClone(source[key], map)
: source[key]
}
return clone
}
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
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
# 21. 快速排序
function quickSort(arr) {
if (arr.length <= 1) return arr
let midIndex = Math.floor(arr.length / 2)
let midVal = arr[midIndex]
let left = []
let right = []
for (let [index, val] of arr.entries()) {
if (index === midIndex) continue
if (val <= midVal) left.push(val)
if (val > midVal) right.push(val)
}
return quickSort(left).concat(midVal, quickSort(right))
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 22. EventBus
class EventBus {
constructor() {
this.events = new Map()
}
on(type, fn) {
this.events.has(type)
? this.events.set(type, [fn, ...this.events.get(type)])
: this.events.set(type, [fn])
}
emit(type, payload) {
if (this.events.has(type)) {
this.events.get(type).forEach((fn) => {
fn(payload)
})
}
}
remove(type, fn) {
if (this.events[type]) {
let index = this.events[type].findIndex((cb) => fn === cb)
if (index != -1) this.events[type].splice(index, 1)
return true
}
return false
}
once() {}
}
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
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
# 23. 异步并发控制
function limitRequest(urls, limit = 5) {
let total = urls.len
let runningCount = 0
let lock = []
let res = []
let block = () => {
return new Promise((resolve) => lock.push(resolve))
}
let done = (value, i) => {
res[i] = value
if (!total) return res
}
let next = () => {
let fn = lock.shift()
fn && fn()
runningCount--
}
let doRequest = (url, i) => {
if (runningCount >= limit) {
await block()
}
runningCount++
fetch(url).then((value) => {
total--
next()
done(value, i)
})
}
for (let [index, url] of urls.entries()) {
doRequest(url, index)
}
}
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
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
# 24. LRU 算法
class LRUCache {
constructor(capacity) {
this.capacity = capacity
this.cache = new Map()
}
get(key) {
if (!this.cache.has(key)) return -1
const value = this.cache.get(key)
this.cache.delete(key)
this.cache.set(key, value)
return value
}
set(key, value) {
// 如果存在,先删除
if (this.cache.has(key)) {
this.cache.delete(key)
} else {
if (this.cache.size === this.capacity) {
// 获取到Map中第一个数据的key值,即最近最少访问的key,删之
const delKey = this.cache.keys().next().value
this.cache.delete(delKey)
}
}
// 最后都要重新设置
this.cache.set(key, 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
25
26
27
28
29
30
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
# 25. promisify
function promisify(fn) {
return function () {
return new Promise((resolve, reject) => {
return fn.call(this, ...arguments, (err, ...args) => {
if (err) reject(err)
resolve(args)
})
})
}
}
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# 26. 简易模板引擎
let data = {
url: 'https://www.bytedance.com/',
title: 'Inspire creativity, enrich life.',
text: 'ByteDance',
}
let strTemp =
'<a href="{url}" title="{title}">{text}</a><a href="{url}" title="{title}">{text}</a>'
function substitute(str, obj) {
let keys = Object.keys(data)
for (let key of keys) {
str = str.replace(new RegExp(`{${key}}`, 'g'), data[key])
}
return str
}
console.log(substitute(strTemp, data))
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