debounce,throttle,copy,flatten实现

409 阅读2分钟

步骤口述参考,实现笔试参考

防抖,节流,拷贝更丰富实现参考lodash

实现debounce

防抖,间隔时间内多次触发,只执行一次(输入校验)

步骤

  • 设置定时器,如果时间没有到触发,重置定时器
  • 返回高阶函数,闭包共享定时器变量

实现

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

实现throttle

节流,间隔时间内多次触发,间隔时间只执行一次(scroll)

步骤

  • 定时器和标记位
  • 触发设置定时器执行,标记位false,不再接受触发设置定时器
  • 定时器回调执行,标记位true,后续触发重复上一步
  • 返回高阶函数(也可以直接记录时间实现,当前时间 和 上一次记录时间 的差)

实现

function throttle(fn, delay) {
  let flag = true;
  return function() {
    if (flag) {
      flag = false;
      setTimeout(() => {
        fn.apply(this, arguments);
        flag = true;
      }, delay);
    }
  }
}

实现shadowCopy

基本类型会产生副本,而引用类型还是共享数据

步骤

  • 扩展运算符...Object.assign

实现

function shadowCopy(source) {
  // return {...source};
  return Object.assign(source);
}

实现deepCopy

生成完成独立的副本,不管什么类型数据

步骤

  • 创建新对象
  • 遍历属性,如果是基本数据类型,直接复制;非基本数据类型,递归调用
  • 特殊类型处理:正则,date,函数,symbol,循环引用等

实现

function deepCopy(source) {
  // 特殊类型,函数不能处理,null忽略,循环引用报错
  // return JSON.parse(JSON.stringify(source)); 
  const getType = obj => {
    return Object.prototype.toString.call(obj).slice(8, -1);
  }
  const getRegExpFlag = re => {
    let flags = '';
    if(re.global) flags += 'g';
    if(re.ignoreCase) flags += 'i';
    if(re.multiline) flags += 'm';
    return flags
  }
  // 循环判断,耗性能
  const parents = [];
  const children = [];
  const _clone = parent => {
    if (parent === null) return null;
    if (typeof parent !== "object") return parent;
    let child, proto;
    switch getType(parent) {
      case 'Array':
        child = [];
        break;
      case 'RegExp':
        child = new RegExp(parent.source, getRegExp(parent));
        if (parent.lastIndex) child.lastIndex = parent.lastIndex;
        break;
      case 'Date':
        child = new Date(parent.getTime());
        break;
      default:
        proto = Object.getPrototypeOf(parent);
        child = Object.create(proto);   
    }
    const index = parents.indexOf(parent);
    if (index != -1) { // 已经存在,避免循环,直接返回
      return children[index];
    }
    parents.push(parent);
    children.push(child);
    for (let i in parent) {
      child[i] = _clone(parent[i]);
    }
    return child;
  }
  return _clone(parent);
}

实现arrFlat

步骤

  • 1、es6自带flat方法,参数为展开层数
  • 2、判断元素是否为数组,递归调用

实现

function flatten(arr, result = []) {
    for (let item of arr) {
        if (Array.isArray(item))
            flatten(item, result)
        else
            result.push(item)
    }
    return result
}
// reduce版
const flatten = arr => 
    arr.reduce((pre, val) => 
        pre.concat(Array.isArray(val) ? flatten(val) : val), []);