前端手写(未完待补充)

93 阅读3分钟

1 实现 compose ✔️

// 用法如下:
function fn1(x) {
  return x + 1;
}
function fn2(x) {
  return x + 2;
}
function fn3(x) {
  return x + 3;
}
function fn4(x) {
  return x + 4;
}
const a = compose(fn1, fn2, fn3, fn4);
console.log(a(1)); // 1 + 4 + 3 + 2 + 1 = 11

实现啦

function compose(...fns) { 
  // compose 返回的是 (...args) => next(prev(...args)) 函数
  return fns.reduce((prev, next) => {
    return (...args) => next(prev(...args));
  });
}

2 setTimeout 模拟实现 setInterval ✔️

setInterval 不可控,比如有个场景,我们要每秒一次轮询后端接口,如果我们使用定时器而且接口比较慢时,比如 3 秒返回一次,那么就可能并行很多无意义请求,服务器压力会很大,改成 setTimeout 去实现,我们可以控制当上个请求结束后,再开始计时,也就是说,我们能实现接口返回后,再间隔一秒去发请求,这样看起来正常了许多。

const newInterval = (func, ms) => {
  let timer = null;

  const inside = () => {
    timer = setTimeout(() => {
      // 包到异步任务里,这样能实现 func();  执行之后,下次任务才开始计时
      func(); 
      inside();
    }, ms);
  }

  inside();

  return () => clearTimeout(timer);
}

测试代码~

function fn() {
  console.log('😘');
}

let timer = newInterval(fn, 1000);

2-2 变形:setInterval 模拟 setTimeout ✔️

const mySetTimeout = (fn, ms) => {
  let timer = setInterval(() => {
    clearInterval(timer);
    fn();
  }, ms);
}

测试

function fn() {
  console.log('🍊');
}
mySetTimeout(fn, 2000);

3 发布订阅模式 ✔️

class eventEmitter {
  constructor() {
    this.eventMap = {};
  }
  
  $on(name, cb) {
    let events = this.eventMap[name];

    if (!events) {
      this.eventMap[name] = [cb]
    } else {
      events.push(cb);
    }
  }

  $emit(name, data) {
    let events = this.eventMap[name];
    
    if (!events) return;

    for (var i = 0; i < events.length; i++) {
      events[i](data);
    }
  }

  // 注册只可以触发一次的事件
  $once(name, cb) {
    const fn = () => {
      cb();
      this.$off(name);
    }
    this.$on(name, fn);
  }

  $off(name) {
    this.eventMap[name] && (delete this.eventMap[name]);
  }
}

测试代码

let e = new eventEmitter();

e.$on('jump', () => console.log('跳起来~'));
e.$on('sayHi', () => console.log('hi~'));
e.$on('sayHi', () => console.log('hi2~'));
e.$once('onceSmile', () => console.log('我只笑一次'));

e.$off('jump');

e.$emit('jump');
e.$emit('sayHi', 'babalala');
e.$emit('onceSmile');
e.$emit('onceSmile');

4. 观察者模式 ✔️

class Sub {
  constructor(name) {
    this.name = name;
    this.watchers = [];
    this.state = '😊';
  }

  add(watcher) {
    this.watchers.push(watcher);
  }

  notify(newState) {
    this.watchers.map(watcher => watcher.update(newState));
  }
}

class Watcher {
  constructor() {
    this.name = name;
  }

  update(newState) {
    console.log('👶🏻新状态来了', newState);
  }
}

测试代码

let parent = new Sub('父亲');
let mom = new Sub('母亲');
let baby = new Watcher('宝宝');

parent.add(baby);
mom.add(baby);

parent.notify('宝宝哭了');

5 数组去重 ✔️

var nums = [1, 1, 2, 3, 4, 4, 5, 6, 5, 3, 0, 1]

// @1 方案1
let res = [...new Set(nums)]

// @2 hash 大法,挨个收集
function removeRepeatElm() {
  let map = {};
  let res = [];

  for (var i = 0; i < nums.length; i++) {
    let cur = nums[i];

    if (!map[cur]) {
      map[cur] = 1;
      res.push(cur);
    }
  }

  return res;
}

console.log(removeRepeatElm(nums));

6 数组扁平化 ✔️

递归解法1

平平无奇,又妙趣横生。

const flatFn = (arr, total = []) => {
  if (!arr.length) return [];
  let toString = Object.prototype.toString;

  for (let i = 0; i < arr.length; i++) {
    if (toString.call(arr[i]) == '[object Array]') {
      flatFn(arr[i], total);
    } else {
      total.push(arr[i]);
    }
  }

  return total;
}

递归解法2

利用 reduce 简化逻辑。

const flatFn = arr => {
  return arr.reduce((pre, cur) => {
    return Array.isArray(cur) ? [...pre, ...flatFn(cur)] : [...pre, cur]
  }, []);
}

迭代解法

不说了,牛逼。

// 巧用 [].concat(1, 2, [3]) => [1, 2, 3]
function flatter(arr) {
  if (!arr.length) return;
  while (arr.some((item) => Array.isArray(item))) {
    arr = [].concat(...arr);
  }
  return arr;
}

7 寄生组合继承 ✔️

function Parent () {
  this.name = 'parent';
}

Parent.prototype = {
  sayName() {
    console.log('i am Parent');
  }
}

function Children() {
  Parent.call(this);
  this.age = 12;
}

Children.prototype = Object.create(Parent.prototype);

const ys = new Children();
console.log(ys);

8 实现有并行限制的 Promise 调度器

9 new 操作符

10 call apppy bind

11 深拷贝(考虑到复制 Symbol 类型)

12 instanceof

13 柯里化

14 冒泡排序--时间复杂度 n^2

15 选择排序--时间复杂度 n^2

16 插入排序--时间复杂度 n^2

17 快排--时间复杂度 nlogn ~ n^2 之间

18 归并排序--时间复杂度 nlog(n)

19 二分查找--时间复杂度 log2(n)

20 实现 LazyMan

21 防抖节流

22 写版本号排序的方法

23 LRU 算法

24 Promise 以及相关方法的实现

25 实现一个 add 方法

26 动态规划求解硬币找零问题

27 请实现 DOM2JSON 一个函数

28 类数组转化为数组的方法

29 Object.is 实现

30 AJAX