手写前端常用工具方法(一)

Promise的简单实现

function myPromise (executor) {
  this.value = null
  this.fail = null
  this.status = 'pending'
  this.onResolvedQueue = []
  this.onRejectedQueue = []

  var _this = this

  function resolve (value) {
    if (_this.status !== 'pending') {
      return
    }
    _this.value = value
    _this.status = 'resolved'
    _this.onResolvedQueue.forEach(resolved => resolved(_this.value))
  }

  funciton reject (error) {
    if (_this.status !== 'pending') {
      return
    }
    _this.fail = error
    _this.status = 'rejected'
    _this.onRejectedQueue.forEach(rejected => rejected(_this.fail))
  }

  executor(resolve, reject)
}

myPromise.prototype.then = function (onResolved, onRejected) {
  if (typeof onResolved !== 'function') {
    onResolved = function (x) {resolve(x)}
  }
  if (typeof onRejected !== 'function') {
    onRejected = function (e) {reject(e)}
  }

  var _this = this

  if (_this.status === 'resolved') {
    onResolved(_this.value)
  } else if (_this.status === 'rejected') {
    onRejected(_this.fail)
  } else {
    _this.onResolvedQueue.push(onResolved)
    _this.onRejectedQueue.push(onReejcted)
  }
  return this
}

节流

function throttle (fn, delay) {
  let last = 0

  return function () {
    let context = this
    let now = +new Date()
    if (now - last >= delay) {
      last = now
      fn.apply(context, arguments)
    }
  }
}

防抖

function debounce (fn, delay) {
  let timer = null

  return function () {
    let context = this
    if (timer) clearTimeout(timer)
    timer = setTimeout(() => {
      fn.apply(context, arguments)
    }, delay)
  }
}

new

function myNew (fn) {
  // 实例
  const res = {}
  if (fn.prototype !== null) {
    res.__proto__ = fn.prototype
  }
  const args = Array.prototype.slice.call(arguments, 1)
  const ret = fn.apply(res, args)
  if ((typeof ret === 'object' || typeof ret === 'function') && ret !== null) {
    return ret
  }
  return res
}

call

Function.prototype.myCall = function (context) {
  context.fn = this
  const args = [...arguments].slice(1)
  const result = context.fn(...args)
  delete context.fn
  return result
}

apply

Funcition.prototype.myApply = function (context) {
  context.fn = this
  let result
  if (arguments[1]) {
    result = context.fn(...arguments[1])
  } else {
    result = context.fn
  }
  delete context.fn
  return result
}

bind

Function.prototype.myBind = function (context) {
  const fn = this
  let args = Array.prototype.slice.call(arguments, 1)
  if (typeof fn !== 'function) {
    throw new TypeError('must be function')
  }
  return function () {
    let fnArgs = args.concat(Array.prototype.slice.call(arguments))
    return fn.apply(args, fnArgs)
  }
}