1、手写EventBus

  1. class EventBus {
  2. constructor() { // 构建map进行事件存储
  3. this.map = new Map();
  4. }
  5. on(name, fn) { // 事件订阅
  6. const fnList = this.map.get(name);
  7. if (fnList) {
  8. fnList.push(fn);
  9. } else {
  10. this.map.set(name, [fn]);
  11. }
  12. }
  13. emit(name, args) { // 事件发布
  14. const list = this.map.get(name);
  15. if (!list) {
  16. return -1
  17. }
  18. list.forEach(fn => fn(args));
  19. }
  20. off(name) { // 事件解除绑定
  21. const flag = this.map.has(name);
  22. if (flag) {
  23. this.map.delete(name);
  24. }
  25. }
  26. once(name, fn) { // 只订阅一次
  27. this.map.set(name, [fn]);
  28. }
  29. }

2、手写async函数

  1. function asyncToGenerator(generator) { // 接收一个generator函数
  2. return () => { // 返回一个函数,通过调用函数返回一个promise
  3. return new Promise((resolve, reject) => {
  4. const gen = generator(); // 让generator函数执行,返回一直迭代器
  5. function step(key, val) { // 定义一个执行函数
  6. let result; // 用一个值接收迭代器执行的结果
  7. try {
  8. result = gen[key](val); // 执行迭代器函数,当key为next时候为正常执行
  9. } catch(err) { // 当key不为next时,抛错,执行reject
  10. reject(err);
  11. }
  12. const [ done, value ] = result; // 将迭代器执行结果解构为done和value
  13. if (done) { // 当执行完成时,执行resolve
  14. resolve(value);
  15. } else { // 当执行未完成时
  16. return Promise.resolve(value) // 将返回值用Promise.resolve包装,继续递归执行
  17. .then(res => step('next', res))
  18. .catch(err => step('err', err));
  19. }
  20. }
  21. step('next'); // 执行自定义函数
  22. })
  23. }
  24. }

3、手写LRU

  1. class LRU {
  2. constructor(max) {
  3. this.map = new Map(); // 存储相关队列
  4. this.max = max; // 最大长度
  5. }
  6. get(key) { // 获取值
  7. const value = this.map.get(key); // 判断已经存在
  8. if (!value) { // 如果不存在
  9. return -1;
  10. }
  11. this.map.delete(key); // 如果存在先将存在的删除
  12. this.map.set(key,value); // 将这个值存放到最后一位
  13. return value; // 返回这个值
  14. }
  15. set(key, value) { // 设置值
  16. const val = this.map.get(key); // 是否存在
  17. if (val) { // 如果存在,将这个存在的指删除
  18. this.map.delete(key);
  19. }
  20. if (this.max >= this.map.size) { // 判断队列长度是否大于等于当前最大值
  21. this.map.delete(this.map.keys().next().value); // 将这个队列的最前面的一个删除
  22. }
  23. this.map.set(key, value); // 将这个值进行存储
  24. }
  25. }

4、promise 最大并发

  1. // 1.写法
  2. class PromisePool {
  3. constructor(max, fn) {
  4. this.max = max; // 最大并发数
  5. this.fn = fn; // 执行的异步函数
  6. this.pool = []; // 并发池
  7. this.urls = []; // 执行的url队列
  8. }
  9. start(urls) { // 开始执行最大并发函数
  10. this.urls = urls; // 传入所有的ur数组
  11. while(this.pool.length < this.max) { // 当并发池的数量小于最大数量
  12. const url = this.urls.shift(); // 拿到第一个url数组
  13. this.setTask(url); // 设置存储函数执行返回的promise
  14. }
  15. return this.run(Promise.race(this.pool)); // 利用Promise.race找到最开始结束的
  16. }
  17. setTask(url) { // 存储函数执行的promise
  18. if (!url) return false;
  19. const task = this.fn(url); // 函数执行返回promise
  20. this.pool.push(task); // 放入执行队列中
  21. task().then(() => { // 利用事件环的方式,执行完成进行并发池数据的删除
  22. this.pool.splice(this.urls.indexOf(task), 1); // 删除并发池
  23. })
  24. }
  25. run(race) { // 执行Promise.race拿到第一个完成的任务
  26. return race.then(() => {
  27. const url = this.urls.shift();
  28. this.setTask(url);
  29. return this.run(Promise.race(this.pool));
  30. })
  31. }
  32. }
  33. // 2.写法
  34. class Scheduler {
  35. list = [];
  36. maxNum = 2;
  37. workingNum = 0;
  38. add(promiseCreator) {
  39. this.list.push(promiseCreator)
  40. }
  41. start() {
  42. for (let i = 0; i < this.maxNum; i++) {
  43. this.doNext();
  44. }
  45. }
  46. doNext() {
  47. if (this.list.length && this.workingNum < this.maxNum) {
  48. this.workingNum ++;
  49. this.list.shift()().then(() => {
  50. this.workingNum --;
  51. this.doNext();
  52. })
  53. }
  54. }
  55. }
  56. const timeout = time => new Promise(resolve => setTimeout(resolve, time));
  57. const scheduler = new Scheduler();
  58. const addTask = (time, order) => {
  59. scheduler.add(() => timeout(time).then(() => console.log(order)));
  60. }
  61. addTask(1000, 1);
  62. addTask(2000, 2);
  63. scheduler.start();
  64. // 3.写法
  65. function asyncPool(poolLimit, array, iteratorFn) {
  66. let i = 0;
  67. const ret = []; // 存储所有的异步任务
  68. const executing = []; // 存储正在执行的任务
  69. const enqueue = function() {
  70. if (i === array.length) {
  71. return Promise.resolve();
  72. }
  73. const item = array[i++];
  74. const p = Promise.resolve().then(() => iteratorFn(item, array));
  75. ret.push(p);
  76. let r = Promise.resolve();
  77. if (poolLimit <= array.length) {
  78. const e = p.then(() => executing.splice(executing.indexOf(e), 1));
  79. executing.push(e);
  80. if (executing.length >= poolLimit) {
  81. r = Promise.race(executing);
  82. }
  83. }
  84. return r.then(() => enqueue());
  85. }
  86. return enqueue().then(() => Promise.all(ret));
  87. }
  88. const timeout = i => new Promise((resolve) => {
  89. setTimeout(() => {
  90. console.log(i);
  91. resolve(i)
  92. }, i)
  93. })
  94. asyncPool(2, [1000, 5000, 3000, 2000], timeout);

5、手写bind

  1. /**
  2. 1、bind方法可以绑定this指向
  3. 2、bind方法返回一个绑定后的函数(高阶函数)
  4. 3、如果绑定的函数被new了,当前函数的this指向当前的实例
  5. */
  6. function myBind(context) {
  7. if (typeof this !== 'function') { // 如果调用不是一个函数就报错
  8. throw new Error('bind must be called on a function');
  9. }
  10. var _this = this; // 保存当前调用的this
  11. var args = Array.prototype.slice.call(arguments, 1); // 截取参数
  12. var nop = function() {}
  13. function F() {
  14. return _this.apply(this instanceof nop ? this : context, [ ...arguments, ...args]);
  15. }
  16. nop.prototype = this.prototype;
  17. F.prototype = new nop();
  18. return F;
  19. }

6、手写call、apply

  1. function myCall(context) {
  2. if (typeof this !== 'function') {
  3. throw new TypeError('error');
  4. }
  5. context = context || window;
  6. const args = [...arguments].slice(1);
  7. context.fn = this;
  8. const result = context.fn(...args);
  9. delete context.fn;
  10. return result;
  11. }
  12. function myApply(context) {
  13. if (typeof this !== 'function') {
  14. throw new TypeError('error');
  15. }
  16. context = context || window;
  17. context.fn = this;
  18. let result
  19. if (arguments[1]) {
  20. result = context.fn(...args);
  21. } else {
  22. result = context.fn();
  23. }
  24. delete context.fn;
  25. return result;
  26. }

7、手写promise.all和promise.allSettled

  1. // Promise.all是必须等到所有成功之后才会成功,如果有一个失败则导致都失败
  2. Promise.all = function(promiseList) { // 传入一个数组
  3. return new Promise((resolve, reject) => { // 返回一个promise
  4. const list = []; // 承载结果的数组
  5. var i = 0; // 计数器
  6. function judge(value, index) { // 判断是否全完的方法
  7. list[index] = value; // 那个完成了,就对应放到数组的第几项
  8. if (++i === promiseList.length) { // 如果计数器和传入数组相同,证明全部执行完成
  9. resolve(list); // 返回结果
  10. }
  11. }
  12. promiseList.forEach((promise, index) => { // 遍历数组
  13. if (promise instanceof Promise) { // 如果是一个promise
  14. promise.then(res => { // 执行promise
  15. judge(res, index); // 正常执行
  16. }).catch(err => {
  17. reject(err); // 失败
  18. })
  19. } else { // 如果不是promise就直接装入数组
  20. judge(promise, index);
  21. }
  22. })
  23. })
  24. }
  25. // Promise.allSettled是所有执行结果都会进行返回,装入一个数组中
  26. Promise.allSettled = function(promiseList) {
  27. let length = promiseList.length; // 记录有多个promise
  28. const result = []; // 承载promise执行结果
  29. return new Promise((resolve, reject) => { // 返回一个promise
  30. for (let i = 0; i < promiseList.length; i++) {
  31. const current = promiseList[i];
  32. current.then(res => {
  33. result.push({ status: 'fulfilled', value: res }); // 将成功的结果装入
  34. }, err => {
  35. result.push({ status: 'rejected', reason: err }); // 将失败的结果装入
  36. }).finally(() => {
  37. if (!--length) { // 当计数器为0时,就证明全部执行完毕
  38. resolve(result); // 返回结果
  39. }
  40. })
  41. }
  42. })
  43. }

8、手写函数柯里化

  1. // es5写法
  2. function curry(fn, args) {
  3. var fnLen = fn.length;
  4. var args = args || [];
  5. return function() {
  6. args = args.concat(Array.prototype.slice.call(arguments));
  7. if (args.length === fn.length) {
  8. return curry.call(this, fn, args);
  9. } else {
  10. return fn.apply(this, args);
  11. }
  12. }
  13. }
  14. // es6 写法
  15. const curry = (fn, arr = []) => args => (arg => (arg.length === fn.length) ? fn(...arg) : curry(fn, arg))
  16. ([ ...arr, ...args]);

9、手写instanceof

  1. Function.prototype.myInstanceOf = function(left, right) {
  2. var proto = left.__proto__; // 获取实例的隐式原型
  3. var prototype = right.prototype; // 获取构造函数的显式原型
  4. while(true) {
  5. if (proto === null) { // 如果隐式原型为null,就返回错误
  6. return false;
  7. }
  8. if (proto === prototype) { // 如果隐式原型和显式原型相同,返回正确
  9. return true;
  10. }
  11. proto = proto.__proto__; // 一直递归找隐式原型的隐式原型
  12. }
  13. }

10、手写new和Object.create

  1. // Object.create
  2. function create(obj) {
  3. function F() {};
  4. F.prototype = obj;
  5. return new F();
  6. }
  7. // new 的实现
  8. function new() {
  9. const obj = {};
  10. const Con = [ ...arguments ].shift(1);
  11. obj.__proto__ = Con.prototype;
  12. const result = Con.apply(obj, [ ...arguments ]);
  13. return result instanceof Object ? result : obj;
  14. }

11、手写截流函数

  1. function throttle(fn, delay) {
  2. let timer = null;
  3. let startTime = Date.now();
  4. return function() {
  5. const currentTime = Date.now();
  6. const remaining = delay - (currentTime - startTime);
  7. const context = this;
  8. const args = Array.prototype.slice.call(arguments);
  9. clearTimeout(timer);
  10. if (remaining < 0) {
  11. fn.apply(context, args);
  12. startTime = Date.now();
  13. } else {
  14. timer = setTimeout() => fn.apply(context, args), remaining);
  15. }
  16. }
  17. }