在现代Web开发中,JavaScript 是不可或缺的编程语言。掌握其核心功能和原理对于开发者至关重要。本文通过手写实现JavaScript的一些关键功能和算法,帮助读者深入理解其工作原理,提升编程技能。无论你是初学者还是有经验的开发者,都能从中受益。
- 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
- /**
- * 模拟 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);
- /**
- * 模拟 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
- /**
- * 模拟 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
- /**
- * 模拟 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
几种常用方式:
- /**
- * 浅拷贝,无脑循环
- * @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"
- /**
- * 深拷贝
- * 深层克隆对象结构
- * @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);
- /**
- * 对象扁平化
- * 将多层嵌套的 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
- // }
- 几种常用方式:
-
- 递归
- 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]
- ##
- console.log([...new Set(array)]);
- /**
- * 数组去重
- * 基于对象实现,也可以使用 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));
- 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'));
- 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']
- );
- /**
- * 异步分片处理并发
- * 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);
- });
- **
- * 事件订阅/发布
- * 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');
- /**
- * 防抖
- * 事件高频触发,间隔 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);
- /**
- * 节流
- * 高频事件触发,间隔 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);
- /**
- * 柯里化
- * 把接受多个参数的函数变换成接受一个单一参数的函数
- * 并返回接受余下的参数且返回结果的新函数
- */
- 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
- 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,
- };