JS手写

158 阅读1分钟

call、apply、bind、promise、节流防抖、Set等手写

call

call作用

官方:把调用一个对象的一个方法,以另一个对象替换当前对象; 我的理解:调用函数的时候改变this指向。

Function.prototype.myCall = function () {
  const ctx = arguments[0] || {}
  ctx.fun = this
  const argv = arguments.slice(1)
  return ctx.fun(...argv)
}

apply

Function.prototype.myApply = function () {
  const ctx = arguments[0]
  ctx.fun = this
  return ctx.fun(...arguments[1])
}

bind

改变this指向但不执行

Function.prototype.myBind = function() {
  ctx = arguments[0] || window;
  const argv = arguments.slice(1)
  ctx.fun = this
  return function() {
    return ctx.fun(...argv)
  }
}

Promise

prototype写法

const STATUS = {
  pending: 'pending',
  fulfilled: 'fulfilled',
  rejected: 'rejected'
}

function myPromise(executor) {
  executor(resolve.bind(this), reject.bind(this))
  this.status = STATUS['pending']
  function resolve(value) {
    if(this.status === STATUS['pending']) {
      this.value = value
      this.onFulfilledCache && this.onFulfilledCache(value)
    }
  }
  function reject(reason) {
    if(this.status === STATUS['pending']) {
      this.reason = reason
      this.onRejectedCache && this.onRejectedCache(reason)
    }
  }
}

myPromise.prototype.then = function(onFulfilled, onRejected) {
  if(this.status === STATUS['fulfilled']) {
    onFulfilled(this.value)
  } else if(this.status === STATUS['rejected']) {
    onRejected(this.reason)
  } else if(this.status === STATUS['pending']){
    this.onFulfilledCache = onFulfilled
    this.onRejectedCache = onRejected
  }
}

class写法

class myPromise2 {
  executor(resolve, reject)
  status = STATUS['pending']

  // resolve和reject为什么要用箭头函数?
  // 如果直接调用的话,普通函数this指向的是window或者undefined
  // 用箭头函数就可以让this指向当前实例对象
  resolve = (value) => {
    if (status === STATUS['pending']) {
      this.value = value
      this.onFulfilledCache && this.onFulfilledCache()
    }
  }

  reject = (reason) => {
    if (status === STATUS['pending']) {
      this.reason = reason
      this.onRejectedCache && this.onRejectedCache()
    }
  }

  then(onFulfilled, onRejected) {
    if (this.status === STATUS['fulfilled']) {
      onFulfilled(this.value)
    } else if (this.status === STATUS['rejected']) {
      onRejected(this.value)
    } else if(this.status === STATUS['pending']) {
      this.onFulfilledCache = onFulfilled
      this.onRejectedCache = onRejected
    }
  }
}

节流防抖

防抖:对一个需要执行的函数,等待一段时间再执行,如果这段时间内又触发了这个函数,则重新计时。

  function debounce(fn, delay = 200) {
    let timer;
    return function () {
      // 重新计时
      timer && clearTimeout(timer);
      timer = setTimeout(fn.bind(this), delay, ...arguments);
    }
  }

节流:对一个需要执行的函数,在一段时间内连续触发时,只执行一次

// 时间戳
function throttle(fn, delay = 200) {
  let pre = Date.now()
  return function () {
    const now = Date.now()
    if (now - pre > delay) {
      fn.call(this, ...arguments)
      pre = now
    }
  }
}

// 定时器
function throttle(fn, delay = 200) {
  let timer
  return function () {
    if(!timer) {
      setTimeout(() => {
        fn.call(this, ...arguments)
        clearTimeout(timer)
      }, delay)
    }
  }
}

手写Set

loading。。。