尝试手撕代码

170 阅读2分钟

1.手写深拷贝

function deepClone(obj) {
  var newObj // 存放深拷贝后的对象
  if(obj && typeof obj !== 'object')// 判断是不是基础数据类型
  {
    newObj = obj
  }
  else if(obj && typeof obj === 'object')
  {
    newObj = obj instanceof Array ? [] : {} // 判断对象类型,数组还是object
    for(let key in obj)
    {
      if(obj.hasOwnProperty(key))// 判断是否有继承的属性
      {
        newObj[key] = deepClone(obj[key])// 循环拷贝对象
      }
      else
      {
        newObj[key] = obj[key]
      }
    }
  }
  return newObj
}

2.call方法

Function.prototype._call = function(context) {
  // 判断context是否存在,如果是null或者undefined就转成window
  context = (context === null || context === undefined) ? window : Object(context)
  // 给context添加一个fn属性,让它的this指向改变
  context.fn = this
  // 将参数用数组存起来,因为第一个参数是context,所以用slice(1)从第二项开始存
  let arg = Array.from(arguments).slice(1)
  // 用result存结果
  let result = context.fn(...arg)
  // 删除该属性
  delete context.fn
  // 返回最终的值
  return result
}

3.apply方法

Function.prototype._apply = function(context, arg) {
  // 判断context是否存在,如果是null或者undefined就转成window
  context = (context === null || context === undefined) ? window : Object(context)
  // 给context添加一个fn属性,让它的this指向改变
  context.fn = this
  // 用result存结果, 判断arg是否存在
  let result = (arg === null) ? context.fn(...arg) : context.fn()
  // 删除该属性
  delete context.fn
  // 返回最终的值
  return result
}

4.bind方法

Function.prototype._bind = function(context) {
  // 判断context是否存在,如果是null或者undefined就转成window
  context = (context === null || context === undefined) ? window : Object(context)
  // 给context添加一个fn属性,让它的this指向改变
  context.fn = this
  // 将参数用数组存起来,因为第一个参数是context,所以用slice(1)从第二项开始存
  let args = [...arguments].splice(1)
  return function() {
    // 将参数用数组存起来,这个参数是调用function时传入的参数
    let newArgs = [...arguments]
    // 用result存结果,用concat将两个参数合并,后面类似apply
    let result = context.fn.apply(context, args.concat(newArgs))
    // 删除属性
    delete context.fn
    // 返回值
    return result
  }
}

5.乞丐版Promise

const PENDING = 'pending'
const RESOLVE = 'resolve'
const REJECT = 'reject'


class Promise{
  constructor(fnc){
    this.state = PENDING
    this.value = undefined
    this.reason = undefined

    let resolve = (data) => {
      if(this.state === PENDING)
      {
        this.value = data
        this.state = RESOLVE
      }
    }

    let reject = (data) => {
      if(this.state === PENDING)
      {
        this.reason = data
        this.state = REJECT
      }
    }
    try{
      fnc(resolve,reject)
    }catch(e){
      reject(e)
    }
  }
  then(onfulfilled, onreject){
    if(this.state === resolve)
    {
      onfulfilled(this.value)
    }
    if(this.state === reject)
    {
      onreject(this.reason)
    }
  }
  
}

module.exports = Promise

6.乞丐版Promise.all

const PromiseAll = (promises) => {
  return new Promise((resolve,reject) => {
    if(!Array.isArray(promises))
    {
      throw new TypeError('error')
    }
    let result = [promises.length]
    let count = 0
    promises.forEach((promise,index) => [
      promise.then((res) => {
        result[index] = res
        count++
        count === promises.length && resolve(result)
      }),(err) => {
        reject(err)
      }
    ])
  })
}

7.防抖

function debounce (fnc,delay) {
  let timer = null
  return function() {
    let context = this
    let arg = arguments
    clearTimeout(timer)
    timer = setTimeout(() => {
      fnc.apply(context,arg);
    },delay)
  }
}

window.addEventListener('resize',debounce(foo,2000)) 

8.节流

function throttle(fnc, delay){
  let timer = null
  return function(){
    let context = this
    let arg = arguments
    if(!timer)
    {
      timer = setTimeout(() => {
        fnc.apply(context,arg)
        timer = null
      },delay)
    }
  }
}

9.函数柯里化

function curryingFun(fn, length) {
  //第一次调用获取函数 fn 参数的长度,后续调用获取 fn 剩余参数的长度
  length = length || fn.length;
  // curryingFun 包裹之后返回一个新函数,接收参数为 …args
  return function (...args) {
    // 新函数接收的参数长度是否大于等于 fn 剩余参数需要接收的长度
    return args.length >= length
      ? // 满足要求,执行 fn 函数,传入新函数的参数
        fn.apply(this, args)
      : // 不满足要求,递归 curryingFun 函数,新的 fn 为 bind 返回的新函数(bind 绑定了…args 参数,未执行),新的 length 为 fn 剩余参数的长度
        curryingFun(fn.bind(this, ...args), length - args.length);
  };
}