Kazaf's blog Kazaf's blog
首页
  • javascript
  • typescript
  • vue
  • react
  • babel
  • nginx
GitHub (opens new window)

Kazaf

前端打字员
首页
  • javascript
  • typescript
  • vue
  • react
  • babel
  • nginx
GitHub (opens new window)
  • JavaScript

    • js-发布订阅模式实现EventBus
    • js-手写数组常用方法的实现
    • 手写JS代码收集
      • 通用柯里化函数
      • call
      • apply
      • bind
      • sleep/delay 函数
      • 数组扁平化的函数 flatten
      • String.prototype.trim
      • 防抖
      • 节流
      • LRU 缓存算法
      • 列表转树
      • 树转列表
      • ajax
      • Promise.all
      • 深拷贝
      • new
      • 继承
      • Promise
    • 工具方法收集
  • Typescript

  • Vue

  • react

  • 前端
  • JavaScript
Kazaf
2022-03-22

手写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

# 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

# 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

# bind

Function.prototype.fakeBind = function (ctx, ...args) {
  return (...rest) => this.call(ctx, ...args, ...rest)
}
1
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

# 数组扁平化的函数 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

# 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

# 节流

// 方式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

# 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

# 列表转树

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

# 树转列表

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

# 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

# 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

# 深拷贝

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

# 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

# 继承

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

# 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
编辑 (opens new window)
#JavaScript
上次更新: 2022/06/30, 23:08:13
js-手写数组常用方法的实现
工具方法收集

← js-手写数组常用方法的实现 工具方法收集→

最近更新
01
React中的受控和非受控组件
09-22
02
nginx基本配置
06-01
03
vue添加水印
05-26
更多文章>
Theme by Vdoing | Copyright © 2021-2022
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式