手写实现

9/3/2021


# 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. Object.create

function create(obj) {
  let _proto = new Object(obj)
  function F() {}
  F.prototype = _proto
  return new F()
}
1
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

# 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

# 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

# 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

# 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

# 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

# 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

# 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

# 12. Promise.reject

Promise.reject = function (reason) {
  return new Promise((_, reject) => {
    reject(reason)
  })
}
1
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

# 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

# 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

# 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

# 17. Promise.prototype.catch

Promise.prototype.catch = function (fn) {
  return this.then(_, fn)
}
1
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

# 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

# 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

# 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

# 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

# 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

# 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

# 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

# 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
Last Updated: 10/21/2024, 4:15:17 PM