Skip to content

手写系列

promise

Javascript
function Promise(fn) {
  this.state = 'pending'
  this.value = null
  this.callbacks = []
  fn(this._resolve.bind(this), this._reject.bind(this))
}

Promise.prototype._resolve = function (value) {
  if (this.state === 'pending') {
    this.state = 'fullfilled'
    this.value = value
    this.callbacks.forEach((fn) => this._handle(fn))
  }
}

Promise.prototype._reject = function (value) {
  if (this.state === 'pending') {
    this.state = 'rejected'
    this.value = value
    this.callbacks.forEach((fn) => this._handle(fn))
  }
}

Promise.prototype._handle = function (callback) {
  if (this.state === 'pending') {
    this.callbacks.push(callback)
    return
  }
  let cb = this.state === 'fullfilled' ? callback.onFullfilled : callback.onRejected
  if (!cb) {
    cb = this.state === 'fullfilled' ? callback.resolve : callback.reject
    cb(this.value)
    return
  }
  let ret
  try {
    ret = cb(this.value)
    cb = this.state === 'fullfilled' ? callback.resolve : callback.reject
  } catch (error) {
    ret = error
    cb = callback.reject
  } finally {
    cb(ret)
  }
}

Promise.prototype.then = function (onFullfilled, onRejected) {
  return new Promise((resolve, reject) => {
    this._handle({
      onFullfilled: onFullfilled || null,
      onRejected: onRejected || null,
      resolve,
      reject,
    })
  })
}

Promise.prototype.catch = function (onError) {
  return this.then(null, onError)
}

Promise.prototype.finally = function (onFinally) {
  if (typeof onFinally !== 'function') return this.then()
  let promise = this.constructor
  return this.then(
    (value) => promise.resolve(onFinally()).then(() => value),
    (reason) =>
      promise.resolve(onFinally()).then(() => {
        throw reason
      })
  )
}

Promise.resolve = function (value) {
  if (value && value instanceof Promise) {
    return value
  } else if (value && value instanceof Object && value.then instanceof Function) {
    const then = value.then
    return new Promise((resolve) => then(resolve))
  } else {
    return new Promise((resolve) => resolve(value))
  }
}

Promise.reject = function (value) {
  if (value && value instanceof Object && value.then instanceof Function) {
    const then = value.then
    return new Promise((resolve, reject) => then(reject))
  } else {
    return new Promise((resolve, reject) => reject(value))
  }
}

Promise.all = function (promiseList) {
  return new Promise((resolve, reject) => {
    const resList = []
    promiseList.forEach((p, index) => {
      p.then(
        (res) => {
          resList[index] = res
          if (resList.length === arr.length) {
            resolve(resList)
          }
        },
        (err) => reject(err)
      )
    })
  })
}

Promise.race = function (promiseList) {
  return new Promise((resolve, reject) => {
    for (let i = 0; i < promiseList.length; i++) {
      Promise.resolve(promiseList[i]).then(
        (res) => {
          resolve(res)
        },
        (err) => {
          reject(err)
        }
      )
    }
  })
}

instanceof

isType

Javascript
function isType(type) {
  return function (o) {
    return Object.prototype.toString.call(o) === `[object ${type}]`
  }
}

call

Javascript
Function.prototype.call2 = function (context) {
  // 首先要获取调用call的函数,用this可以获取
  context.fn = this
  const obj = [].shift.call(arguments)
  obj.fn(...arguments)
  delete obj.fn
}

bind

Javascript
Function.prototype.bind2 = function (o) {
  const context = this
  return function () {
    const symbol = Symbol()
    o[symbol] = context
    o[symbol](...arguments)
    delete o[symbol]
  }
}

new

Javascript
function newObject() {
  var obj = Object.create(null)
  //去除参数里的构造函数
  const Constructor = [].shift.call(arguments)
  obj.__proto__ = Constructor.prototype
  Constructor.apply(obj, arguments)
  return obj
}

function factory(name, age) {
  this.name = name
  this.age = age
}

var obj = newObject(factory, 'xjq', 23)

async

迭代器

EventEmitter

Javascript
class Event {
  constructor() {
    this.event = {}
    this.maxListener = 5
    this.listenerCount = 0
  }
  on(type, fn) {
    if (this.listenerCount >= this.maxListener) {
      throw new Error('事件数量超限')
    }
    let hasEvent = !!this.event[type]
    if (typeof fn === 'function') {
      if (hasEvent) {
        this.event[type].push(fn)
      } else {
        this.event[type] = [fn]
      }
    }
    if (!hasEvent) this.listenerCount++
  }

  once(type, fn) {
    const _this = this
    function newFn() {
      fn(...arguments)
      _this.removeListener(type, newFn)
    }
    this.on(type, newFn)
  }

  emit(type, params) {
    if (this.event[type]) {
      this.event[type].forEach((fn) => fn(params))
    }
  }

  setMaxListeners(count) {
    this.maxListener = count
  }

  listeners(type) {
    return this.event[type] || []
  }

  removeAllListener(type) {
    this.event[type] = null
  }
  removeListener(type, listener) {
    if (this.event[type]) {
      this.event[type] = this.event[type].filter((fn) => listener !== fn)
    }
  }

  addListener(type, fn) {
    this.on(type, fn)
  }
}

const e = new Event()
function a1() {
  console.log('a1')
}

function a2() {
  console.log('a2')
}

e.once('a', a1)
e.on('a', a2)
e.emit('a')
e.emit('a')

防抖

Javascript
function debounce(fn, delay) {
  let timer
  return function (...args) {
    const context = this
    clearTimeout(timer)
    timer = setTimeout(fn.bind(context, ...args), delay)
  }
}

节流

Javascript
function throttle(fn, time) {
  let canCall = true
  return function (...args) {
    if (!canCall) return
    canCall = false
    fn(...args)
    setTimeout(() => {
      canCall = true
    }, time)
  }
}

深拷贝

Javascript
function deepClone(obj, weakMap = new WeakMap()) {
  if (!(obj instanceof Object)) return obj
  var isArray = obj instanceof Array
  var res = isArray ? [] : {}
  if (!isArray) {
    if (weakMap.get(obj)) return obj
    weakMap.set(obj, {}.toString.call(obj))
  }
  for (var key in obj) {
    if (obj.hasOwnProperty(key)) {
      res[key] = deepClone(obj[key], weakMap)
    }
  }
  return res
}

对象合并

Javascript
function getType(o) {
  return Object.prototype.toString.call(o)
}

function deepClone(obj, weakMap = new WeakMap()) {
  if (!(obj instanceof Object)) return obj
  var isArray = obj instanceof Array
  var res = isArray ? [] : {}
  if (!isArray) {
    if (weakMap.get(obj)) return {}
    weakMap.set(obj, {}.toString.call(obj))
  }
  for (var key in obj) {
    if (obj.hasOwnProperty(key)) {
      res[key] = deepClone(obj[key], weakMap)
    }
  }
  return res
}

function merge(a, b) {
  if (getType(a) !== getType(b)) {
    return deepClone(b)
  }
  if (!(a instanceof Object)) {
    return b
  }
  const isArray = a instanceof Array
  const res = isArray ? [] : {}
  for (let key in b) {
    if (b.hasOwnProperty(key)) {
      res[key] = merge(a[key], b[key])
    }
  }
  for (let key in a) {
    if (res[key] === undefined && a.hasOwnProperty(key)) {
      res[key] = deepClone(a[key])
    }
  }
  return res
}

柯里化

Javascript
const add = (args) => args.reduce((a, b) => a + b, 0)

function currying(func) {
  const args = []
  return function result(...rest) {
    if (rest.length) {
      args.push(...rest)
      return result
    } else {
      return func(args)
    }
  }
}

LazyMan

Javascript
const stepObj = {
  eat: async function ({ str }) {
    console.log(str)
  },
  sleep: async function ({ delay }) {
    return sleep(delay)
  },
  sleepFirst: async function ({ delay }) {
    return sleep(delay)
  },
  talk: async function ({ name }) {
    console.log(`I'm ${name}`)
  },
}

async function sleep(delay) {
  return new Promise((r, j) => setTimeout(r, delay))
}

function LazyManConstructor(name) {
  this.step = []
  this.name = name
  this.step.push({ name: 'talk', params: { name } })
  async function fn() {
    while (this.step.length) {
      const { name, params } = this.step.shift()
      if (this.step.length) {
        if (this.step[0].name === 'sleepFirst') {
          const { name: lateName, params: lateParams } = this.step.shift()
          await stepObj[lateName](lateParams)
        }
      }
      await stepObj[name](params)
    }
  }
  setTimeout(fn.bind(this), 0)
  return this
}

LazyManConstructor.prototype.eat = function (str) {
  this.step.push({ name: 'eat', params: { str } })
  return this
}

LazyManConstructor.prototype.sleep = function (delay) {
  this.step.push({ name: 'sleep', params: { delay } })
  return this
}

LazyManConstructor.prototype.sleepFirst = function (delay) {
  this.step.push({ name: 'sleepFirst', params: { delay } })
  return this
}

function LazyMan(name) {
  return new LazyManConstructor(name)
}

排序

插入排序

Javascript
function insert(arr) {
  let len = arr.length
  for (let i = 0; i < len - 1; i++) {
    let preIdx = i
    let current = arr[i + 1]
    while (preIdx >= 0 && current < arr[preIdx]) {
      arr[preIdx + 1] = arr[preIdx]
      preIdx--
    }
    arr[preIdx + 1] = current
  }
  return arr
}

选择排序

Javascript
function selectSort(arr) {
  let len = arr.length
  let temp, minIdx
  for (let i = 0; i < len - 1; i++) {
    minIdx = i
    for (let j = i + 1; j < len; j++) {
      if (arr[minIdx] > arr[j]) {
        minIdx = j
      }
    }
    temp = arr[minIdx]
    arr[minIdx] = arr[i]
    arr[i] = temp
  }
  return arr
}

归并排序

Javascript
function mergeSort(arr) {
  _mergeSort(arr, 0, arr.length - 1)
}

function _mergeSort(arr, l, r) {
  if (l < r) {
    const mid = l + parseInt((r - l) / 2)
    _mergeSort(arr, l, mid)
    _mergeSort(arr, mid + 1, r)
    _merge(arr, l, mid, r)
  }
}

function _merge(arr, l, mid, r) {
  let i = l,
    j = mid + 1
  let k = 0,
    temp = []
  while (i <= mid && j <= r) {
    if (arr[i] > arr[j]) {
      temp[k++] = arr[j++]
    } else {
      temp[k++] = arr[i++]
    }
  }

  while (i <= mid) {
    temp[k++] = arr[i++]
  }

  while (j <= r) {
    temp[k++] = arr[j++]
  }
  for (let i = 0; i < k; i++) {
    arr[l + i] = temp[i]
  }
}

快速排序

Javascript
function quickSort(arr) {
  _quickSort(arr, 0, arr.length - 1)
}
function _quickSort(arr, l, r) {
  if (l > r) return

  let left = l,
    right = r

  let base = arr[left]
  let temp
  while (l != r) {
    while (arr[r] >= base && l < r) {
      r--
    }
    while (arr[l] <= base && l < r) {
      l++
    }

    if (l < r) {
      temp = arr[l]
      arr[l] = arr[r]
      arr[r] = temp
    }
  }
  arr[left] = arr[l]
  arr[l] = base
  _quickSort(arr, left, l - 1)
  _quickSort(arr, l + 1, right)
}

冒泡排序

Javascript
function bubbleSort(arr) {
  let len = arr.length
  for (let i = 0; i < len - 1; i++) {
    for (let j = 0; j < len - i; j++) {
      if (arr[j] > arr[j + 1]) {
        let temp = arr[j]
        arr[j] = arr[j + 1]
        arr[j + 1] = temp
      }
    }
  }
  return arr
}

Redux-thunk

Javascript
function createThunkMiddleware(extraArgument) {
  const middleware =
    ({ dispatch, getState }) =>
    (next) =>
    (action) => {
      if (typeof action === 'function') {
        return action(dispatch, getState, extraArgument)
      }

      return next(action)
    }
  return middleware
}

Released under the MIT License.