加深对 JavaScript 的了解,学习并手写常见高频题目,了解实现原理
欢送大家指导,有不足之处会及时改良

点击此处传送至代码仓库

this

1. bind

/** * 1. bind() 办法创立一个新的函数 * 2. 在 bind() 被调用时,这个新函数的 this 被指定为 bind() 的第一个参数 * 3. new 状况下疏忽第一个参数 * 4. 其余参数将作为新函数的参数,供调用时应用 * @param {object} ctx * @param  {...any} args * @returns {function} 返回一个原函数的拷贝,并领有指定 this 值和初始参数 */Function.prototype.__bind = function (ctx, ...args) {    // 判断 this 是否为 function 类型    if (typeof this !== 'function') throw new TypeError('Error');    // 保留以后 this    const __this = this;    return function F() {        return this instanceof F            ? new __this(...args, ...arguments) // new             : __this.apply(ctx, [...args, ...arguments]); // 间接调用时绑定 this    };};// ------------------------------ 测试 ------------------------------function print() {    console.log(this.name, ...arguments);}const obj = {    name: 'mxin',};// Function.prototype.__bind()console.log('Function.prototype.__bind()');// 间接调用,返回原函数拷贝,this 指向 objconst F = print.__bind(obj, 26);F(178); // mxin, 26, 178// new 状况const _obj = new F(145); // undefined, 26, 145console.log(_obj); // print {}// Function.prototype.bind()console.log('Function.prototype.bind()');const Fn = print.bind(obj, 26);Fn(178); // mxin, 26, 178const __obj = new Fn(145); // undefined, 26, 145console.log(__obj); // print {}

2. call

/** * 模仿 call * 应用一个指定的 this 值和独自给出的一个或多个参数来调用一个函数 * @param {object} ctx * @param  {...any} args * @returns {any} 调用 this 的返回值,若无有返回值,则返回 undefined */Function.prototype.__call = function (ctx, ...args) {    if (typeof this !== 'function') throw new TypeError('Error');    // 思考 null 状况,参数默认赋值会有效    if (!ctx) ctx = window;    // 将 this 函数保留在 ctx 上    ctx.fn = this;    // 传参执行并保留返回值    const res = ctx.fn(...args);    // 删除 ctx 上的 fn    delete ctx.fn;      return res;};// ------------------------------ 测试 ------------------------------function Product(name, price) {    this.name = name;    this.price = price;}// Function.prototype.__call()console.log('Function.prototype.__call()');function Food(name, price) {    Product.__call(this, name, price);    this.category = 'food';}const food = new Food('cheese', 5);console.log(food);// Food {name: "cheese", price: 5, category: "food"}//   category: "food"//   name: "cheese"//   price: 5//   __proto__://     constructor: ƒ Food(name, price)//     __proto__: Object// Function.prototype.call()console.log('Function.prototype.call()');function Toy(name, price) {    Product.call(this, name, price);    this.category = 'toy';}const toy = new Toy('car', 10);console.log(toy);// Toy {name: "car", price: 10, category: "toy"}//   category: "toy"//   name: "car"//   price: 10//   __proto__://     constructor: ƒ Toy(name, price)//     __proto__: Object

3. apply

/** * 模仿 apply * 调用一个具备给定 this 值的函数,以及以一个数组(或类数组对象)的模式提供的参数 * @param {object} ctx * @param {} args */Function.prototype.__apply = function (ctx, args) {    if (typeof this !== 'function') throw new TypeError('Error');    // 思考 null 状况,参数默认赋值会有效    if (!ctx) ctx = window;    // 将 this 函数保留在 ctx 上    ctx.fn = this;    // 传参执行并保留返回值    const result = ctx.fn(...args);    // 删除 ctx 上的 fn    delete ctx.fn;      return result;};// ------------------------------ 测试 ------------------------------const numbers = [5, 6, 2, 3, 7];// Function.prototype.__apply()console.log('Function.prototype.__apply()');const max = Math.max.__apply(null, numbers);console.log(max); // 7// Function.prototype.apply()console.log('Function.prototype.apply()');const min = Math.min.apply(null, numbers);console.log(min); // 2

原型

1. 继承

例举几种比拟罕用的继承形式
/** * 应用 extends 继承 */// 继承类class Vehicle {}class Bus extends Vehicle {}let b = new Bus();console.log(b instanceof Bus); // trueconsole.log(b instanceof Vehicle); // true// 继承一般构造函数function Person() {}class Engineer extends Person {}let e = new Engineer();console.log(e instanceof Engineer); // trueconsole.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); // trueconsole.log(man instanceof Person); // true

2. 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));// instanceofconsole.log('instanceof');console.log(o instanceof C);console.log(o instanceof D);console.log(o instanceof Object);

对象

1. Objcet.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

2. Object.is

  • == 运算不同,== 运算符在判断相等前对两边的变量(如果它们不是同一类型) 进行强制转换 (这种行为的后果会将 "" == false 判断为 true), 而 Object.is不会强制转换两边的值
  • === 运算也不雷同, === 运算符 (也包含 == 运算符) 将数字 -0+0 视为相等 ,而将Number.NaNNaN 视为不相等
/** * 模仿 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')}`); // trueconsole.log(`__is('foo', 'bar'): ${__is('foo', 'bar')}`); // falseconst __foo = { a: 1 };const __bar = { a: 1 };console.log(`__is(__foo, __foo): ${__is(__foo, __foo)}`); // trueconsole.log(`__is(__foo, __bar): ${__is(__foo, __bar)}`); // falseconsole.log(`__is(window, window): ${__is(window, window)}`); // trueconsole.log(`__is([], []): ${__is([], [])}`); // falseconsole.log(`__is(null, null): ${__is(null, null)}`); // true// 特例console.log(`__is(0, -0): ${__is(0, -0)}`); // falseconsole.log(`__is(0, +0): ${__is(0, +0)}`); // trueconsole.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')}`); // trueconsole.log(`Object.is('foo', 'bar'): ${Object.is('foo', 'bar')}`); // falseconst foo = { a: 1 };const bar = { a: 1 };console.log(`Object.is(foo, foo): ${Object.is(foo, foo)}`); // trueconsole.log(`Object.is(foo, bar): ${Object.is(foo, bar)}`); // falseconsole.log(`Object.is(window, window): ${Object.is(window, window)}`); // trueconsole.log(`Object.is([], []): ${Object.is([], [])}`); // falseconsole.log(`Object.is(null, null): ${Object.is(null, null)}`); // true// 特例console.log(`Object.is(0, -0): ${Object.is(0, -0)}`); // falseconsole.log(`Object.is(0, +0): ${Object.is(0, +0)}`); // trueconsole.log(`Object.is(-0, -0): ${Object.is(-0, -0)}`); // trueconsole.log(`Object.is(NaN, 0 / 0): ${Object.is(NaN, 0 / 0)}`); // true

3. 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;}// __newconsole.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// newconsole.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


4. 浅拷贝

几种罕用形式:

  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"

5. 深拷贝

/** * 深拷贝 * 深层克隆对象构造 * @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);

6. 对象扁平化

/** * 对象扁平化 * 将多层嵌套的 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// }

数组

1. 数组扁平化

几种罕用形式:

  1. 递归
  2. Array.prototype.flat()
  3. 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]

2. 数组去重

  • 应用 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));

异步编程

1. 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 __finallynew __Promise((resolve, reject) => {    resolve('mxin');})    .__then(res => {        console.log('__resolve:', res);    })    .__finally(() => {        console.log('__resolve finally');    });// 测试 __reject __catch __finallynew __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'));

2. 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']);

3. 并发

/** * 异步分片解决并发 * 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);});

4. 公布/订阅

/** * 事件订阅/公布 * 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];    }}// ------------------------------ 测试 ------------------------------// Eventconsole.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');

技巧

1. 防抖

/** * 防抖 * 事件高频触发,距离 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);

2. 节流

/** * 节流 * 高频事件触发,距离 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);

3. 柯里化

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

Vue

1. Reactive


参考 Vue 3.0 的实现形式

  • reactive 创立响应式对象
  • effect 副作用
  • computed 计算属性


具体实现思路及演示能够看之前写过的一篇文章,点击传送

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,};

参考资料

  • JavaScript中各种源码实现(前端面试口试必备)
  • 32个手撕JS,彻底解脱高级前端(面试高频)
  • 详解JS函数柯里化