2025年4月18日 星期五 乙巳(蛇)年 正月十九 设为首页 加入收藏
rss
您当前的位置:首页 > 计算机 > 编程开发 > JavaScript

JavaScript进阶:手写代码挑战(二)

时间:02-21来源:作者:点击数:12
城东书院 www.cdsy.xyz

在现代Web开发中,JavaScript 是不可或缺的编程语言。掌握其核心功能和原理对于开发者至关重要。本文通过手写实现JavaScript的一些关键功能和算法,帮助读者深入理解其工作原理,提升编程技能。无论你是初学者还是有经验的开发者,都能从中受益。


12 原型 继承 概念

  • 1. 继承
  • 例举几种比较常用的继承方式
  • /**
  • * 使用 extends 继承
  • */
  • // 继承类
  • class Vehicle {}
  • class Bus extends Vehicle {}
  • let b = new Bus();
  • console.log(b instanceof Bus); // true
  • console.log(b instanceof Vehicle); // true
  • // 继承普通构造函数
  • function Person() {}
  • class Engineer extends Person {}
  • let e = new Engineer();
  • console.log(e instanceof Engineer); // true
  • console.log(e instanceof Person); // true
  • /**
  • * 寄生式组合继承
  • */
  • function Person(name) {
  •   this.name = name;
  • }
  • function Man(name, age) {
  •   Person.call(this, name, age);
  •   this.age = age;
  • }
  • Man.prototype = Object.create(Person.prototype);
  • Man.prototype.constructor = Man;
  • const man = new Man('mxin', 18);
  • console.log(man instanceof Man); // true
  • console.log(man instanceof Person); // true

13、instanceof

  • /**
  • * 模拟 instanceof
  • * 判断 obj.__proto__ 和 __constructor.prototype 是否相等
  • * @param {object} obj 实例对象
  • * @param {function} __constructor 构造函数
  • */
  • function __instanceof(obj, __constructor) {
  •   const prototype = __constructor.prototype;
  •   obj = Object.getPrototypeOf(obj);
  •   while (true) {
  •       if (obj === null) return false;
  •       if (obj === prototype) return true;
  •       obj = Object.getPrototypeOf(obj);
  •   }
  • }
  • // ------------------------------ 测试 ------------------------------
  • function C() {}
  • function D() {}
  • const o = new C();
  • // __instanceof()
  • console.log('__instanceof()');
  • console.log(__instanceof(o, C));
  • console.log(__instanceof(o, D));
  • console.log(__instanceof(o, Object));
  • // instanceof
  • console.log('instanceof');
  • console.log(o instanceof C);
  • console.log(o instanceof D);
  • console.log(o instanceof Object);

14 object.create

  • /**
  • * 模拟 Object.create
  • * 创建一个新对象,使用现有的对象来提供新创建的对象的__proto__
  • * @param {object} prototype 新创建对象的原型对象,为 null 时 只能使用 Object.create()
  • * @param {object} properties 访问器描述符,同 Object.defineProperties 第二个参数
  • * @returns {object}
  • */
  • function __create(prototype, properties) {
  •   if (typeof prototype !== 'object') throw new TypeError('Error');
  •   function Constructor() {}
  •   Constructor.prototype = prototype;
  •   const obj = new Constructor();
  •   if (prototype) obj.constructor = Constructor;
  •   // 设置访问器描述符
  •   if (properties) {
  •       if (typeof properties !== 'object') throw TypeError('Error');
  •       Object.defineProperties(obj, properties);
  •   }
  •   return obj;
  • }
  • // ------------------------------ 测试 ------------------------------
  • const person = {
  •   isHuman: false,
  •   printIntroduction: function () {
  •       console.log(`My name is ${this.name}. Am I human? ${this.isHuman}`);
  •   },
  • };
  • // __create()
  • console.log('__create()');
  • const __me = __create(person);
  • __me.name = '__mxin';
  • __me.isHuman = true;
  • __me.printIntroduction();
  • // Object.create()
  • console.log('Object.create()');
  • const me = Object.create(person);
  • me.name = 'mxin';
  • me.isHuman = true;
  • me.printIntroduction();
  • // 目前创建纯净空对象只有 Object.create(null) 可行,无法模拟
  • const emptyObj = Object.create(null);
  • console.log(emptyObj);
  • // {}
  • //   No properties

15 Object.is

  • == 运算不同,== 运算符在判断相等前对两边的变量(如果它们不是同一类型) 进行强制转换 (这种行为的结果会将 "" == false 判断为 true), 而 Object.is不会强制转换两边的值
  • === 运算也不相同, === 运算符 (也包括 == 运算符) 将数字 -0 和 +0 视为相等 ,而将Number.NaN 与 NaN 视为不相等
  • /**
  • * 模拟 Object.is
  • * 判断两个值是否为同一个值
  • * 1. 都是 undefined
  • * 2. 都是 null
  • * 3. 都是 true 或 false
  • * 4. 都是相同长度的字符串且相同字符按相同顺序排列
  • * 5. 都是相同对象(意味着每个对象有同一个引用)
  • * 6. 都是数字且
  • *   a. 都是 +0
  • *   b. 都是 -0
  • *   c. 都是 NaN
  • *   d. 或都是非零而且非 NaN 且为同一个值
  • * @param {*} x
  • * @param {*} y
  • */
  • function __is(x, y) {
  •   if (x === y) {
  •       return x !== 0 || 1 / x === 1 / y;
  •   } else {
  •       return x !== x && y !== y;
  •   }
  • }
  • // ------------------------------ 测试 ------------------------------
  • // __is()
  • console.log('__is()');
  • console.log(`__is('foo', 'foo'): ${__is('foo', 'foo')}`); // true
  • console.log(`__is('foo', 'bar'): ${__is('foo', 'bar')}`); // false
  • const __foo = { a: 1 };
  • const __bar = { a: 1 };
  • console.log(`__is(__foo, __foo): ${__is(__foo, __foo)}`); // true
  • console.log(`__is(__foo, __bar): ${__is(__foo, __bar)}`); // false
  • console.log(`__is(window, window): ${__is(window, window)}`); // true
  • console.log(`__is([], []): ${__is([], [])}`); // false
  • console.log(`__is(null, null): ${__is(null, null)}`); // true
  • // 特例
  • console.log(`__is(0, -0): ${__is(0, -0)}`); // false
  • console.log(`__is(0, +0): ${__is(0, +0)}`); // true
  • console.log(`__is(-0, -0): ${__is(-0, -0)}`); // true
  • // console.log(`__is(NaN, 0 / 0): ${__is(NaN, 0 / 0)}`); // true
  • // Object.is()
  • console.log('Object.is()');
  • console.log(`Object.is('foo', 'foo'): ${Object.is('foo', 'foo')}`); // true
  • console.log(`Object.is('foo', 'bar'): ${Object.is('foo', 'bar')}`); // false
  • const foo = { a: 1 };
  • const bar = { a: 1 };
  • console.log(`Object.is(foo, foo): ${Object.is(foo, foo)}`); // true
  • console.log(`Object.is(foo, bar): ${Object.is(foo, bar)}`); // false
  • console.log(`Object.is(window, window): ${Object.is(window, window)}`); // true
  • console.log(`Object.is([], []): ${Object.is([], [])}`); // false
  • console.log(`Object.is(null, null): ${Object.is(null, null)}`); // true
  • // 特例
  • console.log(`Object.is(0, -0): ${Object.is(0, -0)}`); // false
  • console.log(`Object.is(0, +0): ${Object.is(0, +0)}`); // true
  • console.log(`Object.is(-0, -0): ${Object.is(-0, -0)}`); // true
  • console.log(`Object.is(NaN, 0 / 0): ${Object.is(NaN, 0 / 0)}`); // true

16 new

  • /**
  • * 模拟 new
  • * 1. 创建原型为 constructor.prototype 的新对象 obj
  • * 2. 执行构造函数,this 指向 obj
  • * 3. 判断构造函数返回值是否为对象,是就返回此对象
  • * 4. 构造函数无返回值返回 obj
  • * @param {function} constructor
  • * @param {...any} args
  • * @returns {object}
  • */
  • function __new(constructor, ...args) {
  •   if (typeof constructor !== 'function') throw new TypeError('Error');
  •   // 创建一个空对象,指定原型为constructor.prototype
  •   const obj = Object.create(constructor.prototype);
  •   // 执行构造函数,绑定this
  •   const result = constructor.apply(obj, args);
  •   // 如果构造函数返回值是一个对象,那么返回该对象, 如果没有就返回 obj
  •   return result && result instanceof Object ? result : obj;
  • }
  • // ------------------------------ 测试 ------------------------------
  • function Person(name, age) {
  •   this.name = name;
  •   this.age = age;
  • }
  • // __new
  • console.log('__new');
  • const __mxin = __new(Person, '__mxin', 18);
  • console.log(__mxin);
  • // Person {name: "__mxin", age: "18"}
  • //     age: "18"
  • //     name: "__mxin"
  • //     __proto__:
  • //         constructor: ƒ Person(name, age)
  • //         __proto__: Object
  • // new
  • console.log('new');
  • const mxin = new Person('mxin', 18);
  • console.log(mxin);
  • // Person {name: "mxin", age: "18"}
  • //     age: "18"
  • //     name: "mxin"
  • //     __proto__:
  • //         constructor: ƒ Person(name, age)
  • //         __proto__: Object

17 浅拷贝

几种常用方式:

  1. 自定义循环
  2. 展开运算符
  3. Object.assign()
  • /**
  • * 浅拷贝,无脑循环
  • * @param {*} targetObj
  • */
  • function shallowClone(targetObj) {
  •   const resObj = {};
  •   for (let key in targetObj) {
  •       resObj[key] = targetObj[key];
  •   }
  •   return resObj;
  • }
  • // ------------------------------ 测试 ------------------------------
  • console.log('shallowClone()');
  • const shallowObj = {
  •   name: 'mxin',
  •   age: 18,
  • };
  • /**
  • * 自定义方法
  • */
  • const a = shallowClone(shallowObj);
  • a.name = '__mxin';
  • a.age = 20;
  • console.log('a', a);
  • // {name: "__mxin", age: 20}
  • //   age: 20
  • //   name: "__mxin"
  • /**
  • * 拓展运算符
  • */
  • const b = { ...a };
  • b.name = '____mxin';
  • b.age = 22;
  • console.log('b', b);
  • // {name: "____mxin", age: 22}
  • //   age: 22
  • //   name: "____mxin"
  • /**
  • * Object.assign()
  • */
  • const c = Object.assign({}, shallowObj)
  • c.name = '______mxin';
  • c.age = 24;
  • console.log('c', c);
  • // {name: "______mxin", age: 24}
  • //   age: 24
  • //   name: "______mxin"
  • // 不影响原有对象
  • console.log('shallowObj', shallowObj);
  • // {name: "mxin", age: 18}
  • //   age: 18
  • //   name: "mxin"

18 深拷贝

  • /**
  • * 深拷贝
  • * 深层克隆对象结构
  • * @param {object} target
  • * @returns {object}
  • */
  • function deepClone(target) {
  •   // 如果不是对象,直接返回本身
  •   if (!isObject(target) || target === null) return target;
  •   // 参数类型校验情况还有很多,没有覆盖全面,可以后期拓展
  •   if (target instanceof Date) return new Date(target);
  •   if (target instanceof RegExp) return new RegExp(target);
  •   const obj = {};
  •   const stack = [
  •       {
  •           parent: obj,
  •           key: null,
  •           data: target,
  •       },
  •   ];
  •   while (stack.length) {
  •       const node = stack.pop();
  •       const parent = node.parent;
  •       const key = node.key;
  •       const data = node.data;
  •       let res = key ? (parent[key] = {}) : parent;
  •       for (const k in data) {
  •           if (data.hasOwnProperty(k)) {
  •               if (isObject(data[k])) {
  •                   stack.push({
  •                       parent: res,
  •                       key: k,
  •                       data: data[k],
  •                   });
  •               } else {
  •                   res[k] = data[k];
  •               }
  •           }
  •       }
  •   }
  •   return obj;
  • }
  • /**
  • * 判断 target 是否为对象
  • * @param {*} target
  • */
  • function isObject(target) {
  •   return Object.prototype.toString.call(target) === '[object Object]';
  • }
  • // ------------------------------ 测试 ------------------------------
  • console.log('deepClone()');
  • const deepObj = {
  •   e: {
  •       f: {
  •           g: {
  •               h: 1,
  •           },
  •       },
  •   },
  •   i: {
  •       j: {
  •           k: {
  •               l: 2,
  •           },
  •       },
  •   },
  • };
  • const d = deepClone(deepObj);
  • d.e.f.g.h = 2;
  • d.i.j.k.l = 4;
  • console.log('d', d);
  • // 不影响原有对象
  • console.log('deepObj', deepObj);

19 对象扁平化

  • /**
  • * 对象扁平化
  • * 将多层嵌套的 key 合并
  • * @param {object} target
  • * @param {string} tempKey
  • * @param {object} res
  • * @returns {object}
  • */
  • function flattenObject(target, tempKey = '', res = {}) {
  •   // 使用 Object.entries() 将键值对转换成数组,确保 key 与 val 的对应关系
  •   for (const [key, val] of Object.entries(target)) {
  •       // 如果 val 是对象,保存合并后的 key 进行递归
  •       if (isObject(val)) {
  •           const tmp = tempKey + key + '.';
  •           flattenObject(val, tmp, res);
  •       } else {
  •           // 当 val 不是对象,合并 key 并对结果对象赋值
  •           const tmp = tempKey + key;
  •           res[tmp] = val;
  •       }
  •   }
  •   return res;
  • }
  • /**
  • * 判断 target 是否为对象
  • * @param {*} target
  • */
  • function isObject(target) {
  •   return Object.prototype.toString.call(target) === '[object Object]';
  • }
  • // ------------------------------ 测试 ------------------------------
  • console.log('flattenObject()');
  • const object = {
  •   d: {
  •       e: {
  •           f: {
  •               g: {
  •                   h: 1,
  •               },
  •           },
  •       },
  •       i: {
  •           j: {
  •               k: {
  •                   l: 2,
  •               },
  •           },
  •       },
  •   },
  • };
  • console.log(flattenObject(object));
  • // {
  • //   d.e.f.g.h: 1
  • //   d.i.j.k.l: 2
  • // }

20 数组扁平化

  • 几种常用方式:
  • 递归
  • Array.prototype.flat()
  • Array.prototype.reduce()
  • /**
  • * 数组扁平化
  • * 判断数组中元素类型,如果是数组类型就递归,否则直接 push 到 res 中
  • * @param {array} target
  • * @param {array} res
  • * @returns {array}
  • */
  • function flattenArray(target, res = []) {
  •   for (const val of target) {
  •       if (Array.isArray(val)) {
  •           flattenArray(val, res);
  •       } else {
  •           res.push(val);
  •       }
  •   }
  •   return res;
  • }
  • /**
  • * 使用 Array.prototype.reduce()
  • * @param {array} target
  • */
  • function flattenArrayByReduce(target) {
  •   const initPre = [];
  •   return target.reduce(
  •       (pre, current) =>
  •           pre.concat(
  •               Array.isArray(current) ? flattenArrayByReduce(current) : current
  •           ),
  •       initPre
  •   );
  • }
  • // ------------------------------ 测试 ------------------------------
  • console.log('flattenArray()');
  • const array = [[0], 1, [2, [3, [4, [5, [6]]]]], [7, [8]]];
  • /**
  • * 递归
  • */
  • console.log(flattenArray(array));
  • // [0, 1, 2, 3, 4, 5, 6, 7, 8]
  • /**
  • * Array.prototype.flat()
  • */
  • console.log(array.flat(Number.MAX_SAFE_INTEGER));
  • // [0, 1, 2, 3, 4, 5, 6, 7, 8]
  • /**
  • * Array.prototype.reduce()
  • */
  • console.log(flattenArrayByReduce(array));
  • // [0, 1, 2, 3, 4, 5, 6, 7, 8]
  • ##

21 数组去重

  • 使用 set
  • console.log([...new Set(array)]);
  • 使用对象,或者将对象换成 map ,需要注意数组中元素的类型
  • /**
  • * 数组去重
  • * 基于对象实现,也可以使用 Map
  • * @param {array} target
  • * @returns {array}
  • */
  • function removeDuplicate(target) {
  •   const temp = {};
  •   for (let i = 0; i < target.length; i++) {
  •       const item = target[i];
  •       if (
  •           Object.prototype.toString.call(item) !== '[object Object]' &&
  •           Object.prototype.toString.call(item) !== '[object Function]' &&
  •           Object.prototype.toString.call(item) !== '[object Symbol]' &&
  •           Object.prototype.toString.call(item) !== '[object Array]'
  •       ) {
  •           if (temp.hasOwnProperty(item)) {
  •               target[i] = target[target.length - 1];
  •               target.length--;
  •               i--;
  •           }
  •       }
  •       temp[item] = item;
  •   }
  •   return target;
  • }
  • // ------------------------------ 测试 ------------------------------
  • console.log('removeDuplicate()');
  • const array = [
  •   1,
  •   1,
  •   '2',
  •   '2',
  •   true,
  •   true,
  •   false,
  •   false,
  •   undefined,
  •   undefined,
  •   null,
  •   null,
  •   Symbol('3'),
  •   Symbol('3'),
  •   {},
  •   {},
  •   [],
  •   [],
  • ];
  • console.log(removeDuplicate(array));

22 promise

  • Promise
    • resolve
    • reject
    • then
    • catch
    • finally
  • Promise.resolve
  • Promise.reject
  • Promise.all
  • promise.race
  • const isFunction = variable => typeof variable === 'function';
  • // 定义Promise的三种状态常量
  • const PENDING = 'pending';
  • const RESOLVE = 'resolved';
  • const REJECTED = 'rejected';
  • class __Promise {
  •   constructor(fn) {
  •       this.__status = PENDING;
  •       // 储存 value,用于 __then 返回
  •       this.__value = null;
  •       // 失败队列,在 __then 时注入,resolve 时触发
  •       this.__rejectedQueues = [];
  •       // 成功队列,在 __then 时注入,resolve 时触发
  •       this.__resolvedQueues = [];
  •       try {
  •           fn(this.__resolve, this.__reject);
  •       } catch (err) {
  •           this.__reject(err);
  •       }
  •   }
  •   __resolve = val => {
  •       const run = () => {
  •           if (this.__status !== PENDING) return;
  •           this.__status = RESOLVE;
  •           // 依次执行成功队列中的函数,并清空队列
  •           const runResolved = value => {
  •               let cb;
  •               while ((cb = this.__resolvedQueues.shift())) {
  •                   cb(value);
  •               }
  •           };
  •           // 依次执行失败队列中的函数,并清空队列
  •           const runRejected = error => {
  •               let cb;
  •               while ((cb = this.__rejectedQueues.shift())) {
  •                   cb(error);
  •               }
  •           };
  •           /*
  •             * 如果 resolve 的参数为 Promise 对象,
  •             * 则必须等待该 Promise 对象状态改变后当前 Promsie 的状态才会改变
  •             * 且状态取决于参数 Promsie 对象的状态
  •             */
  •           if (val instanceof __Promise) {
  •               val.__then(
  •                   value => {
  •                       this.__value = value;
  •                       runResolved(value);
  •                   },
  •                   err => {
  •                       this.__value = err;
  •                       runRejected(err);
  •                   }
  •               );
  •           } else {
  •               this.__value = val;
  •               runResolved(val);
  •           }
  •       };
  •       // 异步调用
  •       setTimeout(run);
  •   };
  •   __reject = err => {
  •       if (this.__status !== PENDING) return;
  •       const run = () => {
  •           this.__status = REJECTED;
  •           this.__value = err;
  •           let cb;
  •           while ((cb = this.__rejectedQueues.shift())) {
  •               cb(err);
  •           }
  •       };
  •       setTimeout(run);
  •   };
  •   __then(onResolved, onRejected) {
  •       const { __value, __status } = this;
  •       return new __Promise((onResolvedNext, onRejectedNext) => {
  •           const resolved = value => {
  •               try {
  •                   if (!isFunction(onResolved)) {
  •                       onResolvedNext(value);
  •                   } else {
  •                       const res = onResolved(value);
  •                       if (res instanceof __Promise) {
  •                           // 如果当前回调函数返回__Promise对象,必须等待其状态改变后在执行下一个回调
  •                           res.__then(onResolvedNext, onRejectedNext);
  •                       } else {
  •                           // 否则会将返回结果直接作为参数,传入下一个 __then 的回调函数,并立即执行下一个 __then 的回调函数
  •                           onResolvedNext(res);
  •                       }
  •                   }
  •               } catch (err) {
  •                   onRejectedNext(err);
  •               }
  •           };
  •           const rejected = error => {
  •               try {
  •                   if (!isFunction(onRejected)) {
  •                       onRejectedNext(error);
  •                   } else {
  •                       const res = onRejected(error);
  •                       if (res instanceof __Promise) {
  •                           res.__then(onResolvedNext, onRejectedNext);
  •                       } else {
  •                           onResolvedNext(res);
  •                       }
  •                   }
  •               } catch (err) {
  •                   onRejectedNext(err);
  •               }
  •           };
  •           if (__status === PENDING) {
  •               this.__resolvedQueues.push(resolved);
  •               this.__rejectedQueues.push(rejected);
  •           }
  •           if (__status === RESOLVE) resolved(__value);
  •           if (__status === REJECTED) rejected(__value);
  •       });
  •   }
  •   __catch(onRejected) {
  •       return this.__then(null, onRejected);
  •   }
  •   __finally(cb) {
  •       return this.__then(
  •           value => __Promise.resolve(cb()).__then(() => value),
  •           reason =>
  •               __Promise.resolve(cb()).__then(() => {
  •                   throw new Error(reason);
  •               })
  •       );
  •   }
  •   static resolve(value) {
  •       // 如果参数是 __Promise 实例,直接返回这个实例
  •       if (value instanceof __Promise) return value;
  •       return new __Promise(resolve => resolve(value));
  •   }
  •   static reject(value) {
  •       return new __Promise((resolve, reject) => reject(value));
  •   }
  •   static all(list) {
  •       return new __Promise((resolve, reject) => {
  •           const values = [];
  •           let count = 0;
  •           for (const [i, p] of list.entries()) {
  •               // 数组参数如果不是 __Promise 实例,先调用 __Promise.resolve
  •               this.resolve(p).__then(
  •                   res => {
  •                       values[i] = res;
  •                       count++;
  •                       // 所有状态都变成 resolved 时返回的 __Promise 状态就变成 resolved
  •                       if (count === list.length) resolve(values);
  •                   },
  •                   err => {
  •                       // 有一个被 rejected 时返回的 __Promise 状态就变成 rejected
  •                       reject(err);
  •                   }
  •               );
  •           }
  •       });
  •   }
  •   static race(list) {
  •       return new __Promise((resolve, reject) => {
  •           list.forEach(p => {
  •               this.resolve(p).__then(
  •                   res => {
  •                       resolve(res);
  •                   },
  •                   err => {
  •                       reject(err);
  •                   }
  •               );
  •           });
  •       });
  •   }
  • }
  • // ------------------------------ 测试 ------------------------------
  • console.log('class __Promise {}');
  • const p1 = new __Promise((resolve, reject) =>
  •   setTimeout(() => {
  •       resolve('mxin');
  •   }, 500)
  • );
  • const p2 = new __Promise((resolve, reject) =>
  •   setTimeout(() => {
  •       resolve('__mxin');
  •   }, 200)
  • );
  • const p3 = new __Promise((resolve, reject) => {
  •   setTimeout(() => {
  •       reject(new Error('mxin3'));
  •   }, 100);
  • });
  • // 测试 __resolve __then __finally
  • new __Promise((resolve, reject) => {
  •   resolve('mxin');
  • })
  •   .__then(res => {
  •       console.log('__resolve:', res);
  •   })
  •   .__finally(() => {
  •       console.log('__resolve finally');
  •   });
  • // 测试 __reject __catch __finally
  • new __Promise((resolve, reject) => {
  •   reject(new Error());
  • })
  •   .__catch(e => {
  •       console.log('__reject:', e);
  •   })
  •   .__finally(() => {
  •       console.log('__reject finally');
  •   });
  • // 测试 static resolve
  • __Promise
  •   .resolve('mxin')
  •   .__then(res => console.log('static resolve:', res))
  •   .__finally(() => console.log('static resolve finally'));
  • // 测试 static reject
  • __Promise
  •   .reject(new Error())
  •   .__catch(res => console.log('static reject:', res))
  •   .__finally(() => console.log('static reject finally'));
  • // 测试 all,可添加 p3 测试 rejected 状态
  • __Promise
  •   .all([p1, p2])
  •   .__then(res => console.log('all resolve:', res))
  •   .__catch(e => console.log('all reject', e))
  •   .__finally(() => console.log('all finally'));
  • // 测试 race,速度快的优先返回并结束, 添加 p3 优先 reject
  • __Promise
  •   .race([p1, p2])
  •   .__then(res => console.log('race resolve:', res))
  •   .__catch(e => console.log('race reject', e))
  •   .__finally(() => console.log('race finally'));

23 async/await

  • const NEXT = 'next';
  • const THROW = 'throw';
  • /**
  • * 模拟 async 函数
  • * 1.generator 分割代码片段
  • * 2.使用一个函数让其自迭代
  • * 3.使用 promise 将 yield 包裹起来
  • * 4.执行下一步的时机由 promise 来控制
  • * @param {*} fn
  • */
  • function __async(fn) {
  •   return function () {
  •       // 获取迭代器实例
  •       const gen = fn.apply(this, arguments);
  •       return new Promise((resolve, reject) => {
  •           // 执行下一步
  •           function _next(value) {
  •               __step(gen, resolve, reject, _next, _throw, NEXT, value);
  •           }
  •           // 抛异常
  •           function _throw(err) {
  •               __step(gen, resolve, reject, _next, _throw, THROW, err);
  •           }
  •           // 首次触发
  •           _next(void 0);
  •       });
  •   };
  • }
  • /**
  • * 执行迭代步骤,处理下次迭代结果
  • * 1.将所有值promise化
  • * 2.当 promise 执行完之后再执行下一步
  • * 3.递归调用 next 函数,直到 done == true
  • */
  • function __step(gen, resolve, reject, _next, _throw, key, arg) {
  •   try {
  •       var info = gen[key](arg);
  •       var value = info.value;
  •   } catch (error) {
  •       return reject(error);
  •   }
  •   // 迭代完成
  •   if (info.done) {
  •       resolve(value);
  •   } else {
  •       Promise.resolve(value).then(_next, _throw);
  •   }
  • }
  • // ------------------------------ 测试 ------------------------------
  • console.log('async');
  • __async(function* () {
  •   const e = yield new Promise(resolve =>
  •       setTimeout(() => {
  •           resolve('e');
  •       }, 1000)
  •   );
  •   const a = yield Promise.resolve('a');
  •   const d = yield 'd';
  •   const b = yield Promise.resolve('b');
  •   const c = yield Promise.resolve('c');
  •   return [a, b, c, d, e];
  • })().then(
  •   res => console.log(res) // ['a', 'b', 'c', 'd', 'e']
  • );

24 并发

  • /**
  • * 异步分片处理并发
  • * 1.通过 limitNum 限制并发的 promise 数量
  • * 2.临时结果保存到 resArr 中
  • * 3.start 返回 promise,全部执行完毕 finally 中 resolve 最终结果
  • */
  • class Limit {
  •   constructor(limitNum, promiseList) {
  •       this.resArr = [];
  •       this.handling = 0;
  •       this.resolvedNum = 0;
  •       this.limitNum = limitNum;
  •       this.promiseList = promiseList;
  •       this.runTime = this.promiseList.length;
  •   }
  •   handle(promise) {
  •       console.log(promise, this.handling);
  •       return new Promise((resolve, reject) => {
  •           promise.then(res => resolve(res)).catch(e => reject(e));
  •       });
  •   }
  •   start() {
  •       const __this = this;
  •       return new Promise(resolve => {
  •           const run = () => {
  •               if (!__this.promiseList.length) return;
  •               __this.handling += 1;
  •               __this
  •                   .handle(__this.promiseList.shift())
  •                   .then(res => {
  •                       __this.resArr.push(res);
  •                   })
  •                   .catch(e => {
  •                       const error = new Error(e);
  •                       __this.resArr.push(error);
  •                   })
  •                   .finally(() => {
  •                       __this.handling -= 1;
  •                       __this.resolvedNum += 1;
  •                       if (__this.resolvedNum === __this.runTime) {
  •                           resolve(__this.resArr);
  •                       }
  •                       run();
  •                   });
  •           };
  •           for (let i = 1; i <= __this.limitNum; i++) {
  •               run();
  •           }
  •       });
  •   }
  • }
  • // ------------------------------ 测试 ------------------------------
  • console.log('Limit');
  • const p1 = new Promise((resolve, reject) => {
  •   setTimeout(() => {
  •       resolve(1);
  •   }, 1000);
  • });
  • const p2 = new Promise((resolve, reject) => {
  •   setTimeout(() => {
  •       resolve(2);
  •   }, 1000);
  • });
  • const p3 = new Promise((resolve, reject) => {
  •   setTimeout(() => {
  •       reject(3);
  •   }, 2000);
  • });
  • const p4 = new Promise((resolve, reject) => {
  •   setTimeout(() => {
  •       resolve(4);
  •   }, 2000);
  • });
  • const p5 = new Promise((resolve, reject) => {
  •   setTimeout(() => {
  •       resolve(5);
  •   }, 3000);
  • });
  • const p6 = new Promise((resolve, reject) => {
  •   setTimeout(() => {
  •       resolve(6);
  •   }, 3000);
  • });
  • const promiseList = [p1, p2, p3, p4, p5, p6];
  • const limit = new Limit(2, promiseList);
  • limit.start().then(res => {
  •   console.log(res);
  • });

25 发布/订阅

  • **
  • * 事件订阅/发布
  • * 1.on 收集 key 对应的回调函数依赖关系,存入 eventList
  • * 2.emit 根据第一个参数判断 key 值,并执行其函数依赖
  • * 3.remove 根据 key 值清空依赖
  • */
  • class __Event {
  •   constructor() {
  •       this.eventList = [];
  •   }
  •   on(key, fn) {
  •       if (!this.eventList[key]) this.eventList[key] = [];
  •       this.eventList[key].push(fn);
  •   }
  •   emit() {
  •       const key = [].shift.call(arguments);
  •       const fns = this.eventList[key];
  •       if (!fns || fns.length === 0) return false;
  •       for (const fn of fns) {
  •           fn.apply(this, arguments);
  •       }
  •   }
  •   remove(key) {
  •       if (!this.eventList[key]) return false;
  •       this.eventList[key] = null;
  •       delete this.eventList[key];
  •   }
  • }
  • // ------------------------------ 测试 ------------------------------
  • // Event
  • console.log('Event');
  • const __event = new __Event();
  • __event.on('name', val => {
  •   console.log(`info: ${val}`);
  •   // info: mxin
  • });
  • __event.on('name', val => {
  •   console.log(`info2: ${val}`);
  •   // info2: mxin
  • });
  • // 触发事件,上面两个回调执行对应代码
  • __event.emit('name', 'mxin');
  • // 移除事件
  • __event.remove('name');
  • // 事件被移除,不再触发
  • __event.emit('name', 'mxin');

26 防抖

  • /**
  • * 防抖
  • * 事件高频触发,间隔 wait 时长执行回调
  • * @param {*} fn
  • * @param {*} wait
  • */
  • function debounce(fn, wait) {
  •   let timeout;
  •   return function () {
  •       let __this = this,
  •           args = arguments;
  •       if (timeout) clearTimeout(timeout);
  •       timeout = setTimeout(() => {
  •           fn.apply(__this, args);
  •       }, wait);
  •   };
  • }
  • // ------------------------------ 测试 ------------------------------
  • // debounce()
  • console.log('debounce()');
  • window.onresize = debounce(function () {
  •   console.log('改变窗口大小完毕 1000ms 后触执行');
  • }, 1000);

27 节流

  • /**
  • * 节流
  • * 高频事件触发,间隔 delay 时间执行一次回调
  • * @param {*} fn
  • * @param {*} delay
  • */
  • function throttle(fn, delay) {
  •   const prevTime = Date.now();
  •   return function () {
  •       const curTime = Date.now();
  •       if (curTime - prevTime > delay) {
  •           fn.apply(this, arguments);
  •           prevTime = curTime;
  •       }
  •   };
  • }
  • // ------------------------------ 测试 ------------------------------
  • // throttle()
  • console.log('throttle()');
  • window.onresize = throttle(function () {
  •   console.log('间隔 1000ms 执行一次');
  • }, 1000);

28 柯里化

  • /**
  • * 柯里化
  • * 把接受多个参数的函数变换成接受一个单一参数的函数
  • * 并返回接受余下的参数且返回结果的新函数
  • */
  • function curry() {
  •   const args = [...arguments];
  •   const fn = function () {
  •       args.push(...arguments);
  •       return fn;
  •   };
  •   fn.toString = () => {
  •       return args.reduce((pre, current) => pre + current);
  •   };
  •   return fn;
  • }
  • // ------------------------------ 测试 ------------------------------
  • // curry
  • console.log('curry()');
  • console.log(curry(1)(2)(3)); // 6
  • console.log(curry(1, 2, 3)(4)); // 10
  • console.log(curry(1)(2)(3)(4)(5)); // 15
  • console.log(curry(2, 6)(1)); // 9

29 vue Reactive ​

  • const reactiveMap = new WeakMap();
  • const targetMap = new WeakMap();
  • const effectStack = [];
  • /**
  • * 副作用函数
  • * @param {*} fn
  • */
  • function effect(fn) {
  •   try {
  •       // 将需要执行的effect入栈
  •       effectStack.push(fn);
  •       // 执行该effect,进入proxy的get拦截
  •       return fn();
  •   } finally {
  •       // 依赖收集完毕及所有get流程走完,当前effect出栈
  •       effectStack.pop();
  •   }
  • }
  • /**
  • * 依赖收集
  • * @param {*} target
  • * @param {*} key
  • */
  • function track(target, key) {
  •   // 初始化依赖Map
  •   let depsMap = targetMap.get(target);
  •   if (!depsMap) {
  •       targetMap.set(target, (depsMap = new Map()));
  •   }
  •   // 第二层依赖使用Set存放key对应的effect
  •   let dep = depsMap.get(key);
  •   if (!dep) {
  •       targetMap.get(target).set(key, (dep = new Set()));
  •   }
  •   // 取当前栈中的effect存入第二层依赖中
  •   const activeEffect = effectStack[effectStack.length - 1];
  •   activeEffect && dep.add(activeEffect);
  • }
  • /**
  • * 触发响应,执行effect
  • * @param {*} target
  • * @param {*} key
  • */
  • function trigger(target, key) {
  •   const depsMap = targetMap.get(target);
  •   if (depsMap) {
  •       const effects = depsMap.get(key);
  •       effects && effects.forEach(run => run());
  •   }
  • }
  • /**
  • * 定义响应式对象,返回proxy代理对象
  • * @param {*} object
  • */
  • function reactive(object) {
  •   if (reactiveMap.has(object)) return reactiveMap.get(object);
  •   const proxy = new Proxy(object, handlers);
  •   reactiveMap.set(object, proxy);
  •   return proxy;
  • }
  • /**
  • * 处理器对象,定义捕获器
  • */
  • const handlers = {
  •   set(target, key) {
  •       Reflect.set(...arguments);
  •       trigger(target, key);
  •   },
  •   get(target, key) {
  •       track(target, key);
  •       return typeof target[key] === 'object'
  •           ? reactive(target[key])
  •           : Reflect.get(...arguments);
  •   },
  • };
  • /**
  • * 计算属性
  • * @param {*} fn
  • */
  • function computed(fn) {
  •   return {
  •       get value() {
  •           return effect(fn);
  •       },
  •   };
  • }
  • module.exports = {
  •   effect,
  •   reactive,
  •   computed,
  • };
城东书院 www.cdsy.xyz
方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
栏目更新
栏目热门
本栏推荐