节流和防抖

const debounce = (fn, time) => {
    let timer
    return () => {
        if(timer){
            clearTimeout(timer)
        }
        timer = setTime(fn, time)
    }
}
 
const throttle = (fn, time) => {
    let prev = 0
    return () => {
        const now = Date.now()
        if(now - prev >= time){
            fn()
            prev = now
        }
    }
}
//debounce.js
 
/**
 * @param {*} fn 要执行的函数
 * @param {*} delay 延迟时间
 * @param {*} immediate 是否立即执行
 * @returns 
 */
function debounce(fn, delay, immediate = false) {
  // 1.定义一个定时器, 保存上一次的定时器
  let timer = null;
  let isInvoke = false; //记录立即执行是否已执行过
 
  // 2.真正执行的函数
  const _debounce = function (...args) {
    // 取消上一次的定时器
    if (timer) clearTimeout(timer);
 
    // 判断是否需要立即执行
    if (immediate && !isInvoke) {
      fn.apply(this, args);
      isInvoke = true;
    } else {
      // 延迟执行
      timer = setTimeout(() => {
        // 外部传入的真正要执行的函数
        fn.apply(this, args);
 
        //没有这个步骤时,只有第一次输入是立即执行,即使后面延迟执行后再输入也是延迟执行;
        // 有这个步骤时,第一次输入时立即执行,后面延迟执行后再输入也会有立即执行
        isInvoke = false
        timer = null
      }, delay);
    }
  };
 
  return _debounce;
}
function myThrottle(fn, interval, immediate = true){
    let startTime = 0
 
    const _throttle = function(...args){
        const nowTime = new Date().getTime()
        
        if(!immediate && startTime === 0){
            startTime = nowTime
        }
 
        const waitTime = interval - (nowTime - startTime)
        if(waitTime <= 0){
            fn.apply(this,args)
            startTime = nowTime
        }
    }
 
    return _throttle
}

函数柯理化

const curry = (fn) => 
  curried = (...args) => 
    args.length >= fn.length 
      ? fn(...args) 
      : (...nextArgs) => curried(...args, ...nextArgs);
 
// 结合 compose 或 pipe 实现复杂逻辑
// 组合多个函数
const compose = (...fns) => x => fns.reduceRight((v, f) => f(v), x);
 
// 柯里化处理数据流
const toUpperCase = str => str.toUpperCase();
const exclaim = str => str + '!';
const emphasize = compose(curry(exclaim), curry(toUpperCase));
 

class转es5

手写instanceof

function myInstanceof(source, ctor) {
  /** 判断非引用类型 */
  if (!["function", "object"].includes(typeof source) || source === null) return false
 
  /** 查找原型链 */
  let proto = Object.getPrototypeOf(source)
  while (true) {
    if (proto === null) return false
    if (proto === ctor.prototype) return true
    proto = Object.getPrototypeOf(proto)
  }
}

手写call、bind

Function.prototype.myCall = function (ctx, ...args) {
  // 参数归一化
  ctx = ctx === undefined || ctx === null ? globalThis : Object(ctx)
 
  // 拿到要执行的函数
  const fn = this
 
  // 绑定函数到ctx,(优化:不能被遍历到)
  const key = Symbol("function_call")
  Object.defineProperty(ctx, key, {
    value: fn,
    enumerable: false,
  })
 
  // 执行函数并返回对应的结果
  const result = ctx[key](...args)
  delete ctx[key]
  return result
}
 
function test(a, b) {
  console.log(this, a, b, this.name)
  return a + b
}
 
console.log(test.myCall({ name: "tttt" }, 1, 3))
 
Function.prototype.myBind = function (ctx, ...args) {
  // 要执行的函数
  const fn = this
 
  return function A(...rest) {
    // 如果是 new 调用的,保留new的行为
    if (Object.getPrototypeOf(this) === A.prototype) {
      // 或者 this instanceof A
      return new fn(...args, ...rest)
    }
 
    // 执行函数并返回结果
    return fn.apply(ctx, [...args, ...rest])
  }
}
 
function test(a, b, c, d) {
  console.log(this, a, b, c, d)
  return a + b
}
 
const newFn = test.myBind({ name: "aa" }, 1, 2)
console.log(newFn(3, 4))
console.log(new newFn(3, 4))
 

手写深拷贝

function deepClone(obj) {
  // 如果是 值类型 或 null,则直接return
  if(typeof obj !== 'object' || obj === null) {
    return obj
  }
 
  // 定义结果对象
  let copy = {}
 
  // 如果对象是数组,则定义结果数组
  if(obj instanceof Array) {
    copy = []
  }
 
  // 遍历对象的key
  for(let key in obj) {
    // 如果key是对象的自有属性
    if(obj.hasOwnProperty(key)) {
      // 递归调用深拷贝方法
      copy[key] = deepClone(obj[key])
    }
  }
 
  return copy
}