防抖

// 防抖
(() => {
  const debounce = (fn: Function, delay = 1000): Function => {
    let timer;
    return function (...args) {
      if (timer) {
        clearTimeout(timer);
      }
      timer = setTimeout(() => {
        fn.apply(this, args);
      }, delay);
    };
  };
  const d = debounce((a) => {
    console.log(a);
  }, 300);
  setInterval(() => {
    d('sssss');
  }, 350);
})();

节流

// 节流
(() => {
  const throttle = (fn: Function, delay = 1000) => {
    let flag = false;
    return function (...args) {
      if (flag) return;
      setTimeout(() => {
        fn.apply(this, args);
        flag = false;
      }, delay);
      flag = true;
    };
  };

  const t = throttle((name) => {
    console.log(name);
  }, 1000);
  setInterval(() => {
    t('chenzilin');
  }, 1);
})();

New

// new
(() => {
  const New = function (fn: Function, ...args) {
    const obj = Object.create(fn.prototype);
    const res = fn.apply(obj, args);
    if (typeof res === 'function' || (typeof res === 'object' && res !== null)) {
      return res;
    }
    return obj;
  };

  function Person(name, age) {
    this.name = name;
    this.age = age;
  }
  Person.prototype.sayName = function () {
    console.log(this.name);
  };

  const obj = New(Person, 'czl', 18);
  console.log(obj);
  obj.sayName();

  function TestFun() {
    this.name = 'ccc';
    return {
      name: 'aaa'
    };
  }

  const tf = New(TestFun);
  console.log(tf);
})();

Bind

// bind
(() => {
  Function.prototype.bind2 = function (context, ...args1) {
    // this指向调用的函数
    const fn = this;
    const resFn = function (...args2) {
      // this指向对象
      return fn.apply(this instanceof fn ? this : context, args1.concat(args2));
    };
    resFn.prototype = Object.create(fn.prototype);
    return resFn;
  };

  const obj = {};

  const Person = function (name, age) {
    this.name = name;
    this.age = age;
  };
  Person.prototype.sayName = function () {};

  const p = Person.bind2(obj, 'czl');
  p(19);
  console.log(obj);

  const o = new p(29);
  console.log(o);
  console.log(o.sayName);
})();

Call

// call
(() => {
  Function.prototype.call2 = function (context, ...args) {
    const key = Symbol('key');
    context[key] = this;
    const res = context[key](...args);
    delete context[key];
    return res;
  };

  const obj = {
    name: '',
    age: 0
  };
  function Person(name, age) {
    this.name = name;
    this.age = age;
  }

  Person.call2(obj, 'czl', 19);

  console.log(obj);
})();

Apply

// apply
(() => {
  Function.prototype.apply2 = function (context, args) {
    const key = Symbol('key');
    context[key] = this;
    const res = context[key](...args);
    delete context[key];
    return res;
  };
  const obj = {
    name: '',
    age: 0
  };
  function Person(name, age) {
    this.name = name;
    this.age = age;
  }

  Person.apply2(obj, ['czl', 29]);

  console.log(obj);
})();

DeepClone

// 深拷贝
(() => {
  const deepClone = (target, cache = new WeakMap()) => {
    if (!(target instanceof Object)) return target;

    if (cache.has(target)) {
      return cache.get(target);
    } else if (target instanceof Date) return new Date(target);
    else if (target instanceof RegExp) return new RegExp(target.source, target.flags);

    const res = Array.isArray(target) ? [] : {};
    cache.set(target, res);

    Object.keys(target).forEach((key) => {
      if (target[key] instanceof Object) {
        res[key] = deepClone(target[key], cache);
      } else {
        res[key] = target[key];
      }
    });
    return res;
  };

  const obj = {
    name: 'zhangsan',
    hobby: {
      basketball: true,
      swim: true
    },
    cars: ['玛莎拉蒂', '保时捷', '布加迪威龙'],
    say() {
      console.log(this.name);
    },
    obj: null
  };
  obj.obj = obj;

  // 浅拷贝
  // const copyObj = Object.assign({}, obj);
  // copyObj.name = 'lisi';
  // console.log(obj.name);
  // copyObj.hobby.basketball = false;
  // console.log(obj.hobby.basketball);
  // copyObj.cars.splice(2, 1);
  // console.log(obj.cars);

  const newObj = deepClone(obj);
  newObj.name = 'lisi';
  console.log(obj.name);
  newObj.hobby.basketball = false;
  console.log(obj.hobby.basketball);
  newObj.cars.splice(2, 1);
  console.log(obj.cars);
  newObj.obj = 123;
  console.log(obj.obj);
})();

柯里化

// 柯里化
(() => {
  const curry = function (fn: Function) {
    return function curried(...args1) {
      if (args1.length >= fn.length) {
        return fn.apply(this, args1);
      }
      return function (...args2) {
        return curried.apply(this, args1.concat(args2));
      };
    };
  };

  const sum = (a, b, c) => {
    return a + b + c;
  };
  const currySum = curry(sum);
  console.log(currySum(1)(2, 3));
})();

ES5继承

// es5继承
(() => {
  function Person(name) {
    this.name = name;
  }
  Person.prototype.sayName = function () {
    console.log(this.name);
  };
  function Children(name, age) {
    Person.call(this, name);
    this.age = age;
  }
  Children.prototype.sayAge = function () {
    console.log(this.age);
  };
  Object.setPrototypeOf(Children.prototype, Person.prototype);
  Children.prototype.constructor = Children;

  const zs = new Children('张三', 20);
  zs.sayName();
  zs.sayAge();
})();

ES6继承

// es6继承
(() => {
  class Person {
    constructor(private name) {}
    sayName() {
      console.log(this.name);
    }
    static callMe() {
      console.log('callMe');
    }
  }
  class Children extends Person {
    constructor(name, private age) {
      super(name);
    }
    sayAge() {
      console.log(this.age);
    }
    static callMe() {
      console.log('callMe111');
    }
  }

  const zs = new Children('张三', 20);
  zs.sayName();
  zs.sayAge();
  Children.callMe();
})();

InstanceOf

// instanceof
(() => {
  function myInstanceof(left, right: Function) {
    let proto = left.__proto__;
    let prototype = right.prototype;
    while (true) {
      if (proto === prototype) return true;
      else if (!proto) return false;
      proto = proto.__proto__;
    }
  }
  console.log(myInstanceof({}, Object));
  console.log(myInstanceof([], Object));
  console.log(myInstanceof({}, Array));
})();

数组扁平化

// 数组扁平化
(() => {
  const flattening = (arr: any[]) => {
    return arr.reduce((pre, cur) => (Array.isArray(cur) ? [...pre, ...flattening(cur)] : [...pre, cur]), []);
  };

  console.log(flattening([1, [3, 4, [5]], 8]));
})();

数组去重

// 数组去重
(() => {
  const uniqueArr = (arr: any[]) => {
    return [...new Set(arr)];
  };
  console.log(uniqueArr([1, 2, 3, 1, 2, 3, 4, 4, 4, 7, 7, 7, 2]));
})();

对象扁平化

// 对象扁平化
(() => {
  const flatObj = (obj) => {
    const res = {};
    function process(key, value) {
      if (!(value instanceof Object)) {
        res[key] = value;
      } else if (Array.isArray(value)) {
        value.forEach((item, index) => {
          process(`${key}[${index}]`, item);
        });
      } else if (value instanceof Object) {
        for (let k in value) {
          process(key ? `${key}.${k}` : `${k}`, value[k]);
        }
      }
    }
    process('', obj);
    return res;
  };
  function isObjectValueEqual(a, b) {
    var aProps = Object.getOwnPropertyNames(a);
    var bProps = Object.getOwnPropertyNames(b);

    if (aProps.length != bProps.length) {
      return false;
    }

    for (var i = 0; i < aProps.length; i++) {
      var propName = aProps[i];
      var propA = a[propName];
      var propB = b[propName];
      if (propA !== propB) {
        return false;
      }
    }
    return true;
  }

  // 实现一个 flatten 函数,实现如下的转换功能
  const obj = {
    a: 1,
    b: [1, 2, { c: true }],
    c: { e: 2, f: 3 },
    g: null
  };
  // 转换为
  let objRes = {
    a: 1,
    'b[0]': 1,
    'b[1]': 2,
    'b[2].c': true,
    'c.e': 2,
    'c.f': 3,
    g: null
  };

  console.log(flatObj(obj));
  console.log(Object.is(flatObj(obj), objRes)); // false
  console.log(isObjectValueEqual(flatObj(obj), objRes)); // true
})();

JSON.parse

// JSON.parse
(() => {
  const parse = (target: string) => {
    return eval(`(${target})`);
  };

  const obj = {
    name: 'czl',
    age: 19,
    interests: ['a', 'b', 'c']
  };
  const st = JSON.stringify(obj);
  console.log(st);
  console.log(parse(st));
})();

JSON.stringify

// JSON.stringify
(() => {
  const getType = (target) => {
    return typeof target === 'symbol' ? 'Symbol_basic' : Object.prototype.toString.call(target).slice(8, -1);
  };
  const isObject = (o) => {
    return o !== null && (typeof o === 'object' || typeof o === 'function');
  };
  const processOtherTypes = (target, type: string) => {
    switch (type) {
      case 'String':
        return `"${target.valueOf()}"`;
      case 'Number':
      case 'Boolean':
        return target.valueOf().toString();
      case 'Symbol':
      case 'Error':
      case 'RegExp':
        return '{}';
      case 'Date':
        return `"${target.toJSON()}"`;
      case 'Function':
        return undefined;
      default:
        return null;
    }
  };
  // 检查循环引用
  const checkCircular = (obj, currentParent) => {
    let type = getType(obj);
    if (type === 'Object' || type === 'Array') {
      if (currentParent.includes(obj)) {
        throw new TypeError('Converting circular structure to JSON');
      }
      currentParent.push(obj);
    }
  };
  const jsonStringify = (target, initParent = [target]) => {
    let type = getType(target);
    const iterableList = ['Object', 'Array', 'Arguments', 'Set', 'Map'];
    const specialList = ['Undefined', 'Symbol_basic', 'Function'];
    if (!isObject(target)) {
      if (type === 'Symbol_basic' || type === 'Undefined') {
        return undefined;
      } else if (Number.isNaN(target) || target === Infinity || target === -Infinity) {
        return 'null';
      } else if (type === 'String') {
        return `"${target}"`;
      }
      return String(target);
    } else {
      let res;
      // 针对new String()这种不可迭代的对象
      if (!iterableList.includes(type)) {
        res = processOtherTypes(target, type);
      }
      // 可迭代对象
      else {
        // Array
        if (type === 'Array') {
          res = target.map((item) => {
            if (specialList.includes(getType(item))) {
              return 'null';
            } else {
              // 判断循环引用
              let currentParant = [...initParent];
              checkCircular(item, currentParant);
              return jsonStringify(item, currentParant);
            }
          });
          res = `[${res}]`.replace(/'/g, '"');
        }
        // Object
        else {
          res = [];
          Object.keys(target).forEach((key) => {
            if (getType(key) !== 'Symbol_basic') {
              let type = getType(target[key]);
              if (!specialList.includes(type)) {
                let currentParant = [...initParent];
                checkCircular(target[key], currentParant);
                res.push(`"${key}":${jsonStringify(target[key], currentParant)}`);
              }
            }
          });
          res = `{${res}}`.replace(/'/g, '"');
        }
      }
      return res;
    }
  };

  console.log(jsonStringify(() => {})); // undefined
  console.log(jsonStringify(undefined)); // undefined
  console.log(jsonStringify('123')); // '"123"'
  console.log(jsonStringify(123)); // '123'
  console.log(jsonStringify(null)); // 'null'
  console.log(jsonStringify(Symbol('key'))); // undefined
  console.log(jsonStringify(NaN)); // null
  console.log(jsonStringify(true)); // 'true'
  console.log(jsonStringify({ x: 5 })); // '{"x": 5}'
  console.log(jsonStringify([1, 'false', false]));
  console.log(jsonStringify({ b: undefined }));
  console.log(jsonStringify({ b: 'name' }));
  console.log(jsonStringify(Symbol('name'))); // undefined
  console.log(jsonStringify([Symbol('name'), Symbol('name'), Symbol('name')])); // [null, null, null]
  console.log(jsonStringify(/test/)); // {}
  console.log(jsonStringify(new Error('error'))); // {}
  const map = new Map();
  map.set('name', '张三');
  console.log(jsonStringify(map)); // {}
  console.log(jsonStringify({ name: [1, '2', true, null, undefined, Symbol('key'), function say() {}, /123/, [], new Error('error'), new Map(), new Set()] }));
})();

事件触发器

// 事件触发器
(() => {
  class EventEmitter {
    cache: Record<string, Function[]> = {};
    on(name: string, fn: Function) {
      const tasks = this.cache[name];
      if (!tasks) {
        this.cache[name] = [fn];
      } else {
        this.cache[name].push(fn);
      }
    }
    emit(name: string, once = false) {
      const tasks = this.cache[name].slice();
      if (tasks) {
        tasks.forEach((fn) => {
          fn();
        });
        if (once) {
          delete this.cache[name];
        }
      }
    }
    off(name: string, fn: Function) {
      const tasks = this.cache[name];
      if (tasks) {
        const index = tasks.findIndex((f) => f === fn);
        if (index !== -1) {
          tasks.splice(index, 1);
        }
      }
    }
  }

  const task1 = () => {
    console.log('task1');
  };
  const task2 = () => {
    console.log('task2');
  };

  const event = new EventEmitter();
  event.on('task', task1);
  event.on('task', task2);
  event.off('task', task2);
  setTimeout(() => {
    event.emit('task');
  }, 1000);
})();

Promise

// es6 Promise
(() => {
  const PENDING = 'pending';
  const FULFILLED = 'fulfilled';
  const REJECTED = 'rejected';

  const resolvePromise = (promise2, x, resolve, reject) => {
    if (promise2 === x) {
      reject(new TypeError('检测Promise循环引用'));
    } else if (x instanceof MyPromise) {
      x.then(resolve, reject);
    } else {
      resolve(x);
    }
  };

  class MyPromise {
    status = PENDING;
    value: string;
    reason = null;
    resolveCallbackList = [];
    rejectCallbackList = [];

    constructor(private fn) {
      try {
        fn(this.resolve, this.reject);
      } catch (error) {
        this.reject(error);
      }
    }

    resolve = (value) => {
      if (this.status === PENDING) {
        this.status = FULFILLED;
        this.value = value;
        while (this.resolveCallbackList.length) {
          this.resolveCallbackList.shift()(this.value);
        }
      }
    };

    reject = (reason) => {
      if (this.status === PENDING) {
        this.status = REJECTED;
        this.reason = reason;
        while (this.rejectCallbackList.length) {
          this.rejectCallbackList.shift()(this.reason);
        }
      }
    };

    then(onFulfilled, onRejected = null) {
      const realOnFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (value) => value;
      const realOnRejected =
        typeof onRejected === 'function'
          ? onRejected
          : (reason) => {
              throw reason;
            };

      const promise2 = new MyPromise((resolve, reject) => {
        const microtaskFulfilled = () => {
          queueMicrotask(() => {
            try {
              const x = realOnFulfilled(this.value);
              resolvePromise(promise2, x, resolve, reject);
            } catch (error) {
              reject(error);
            }
          });
        };
        const microtaskRejected = () => {
          queueMicrotask(() => {
            try {
              const x = realOnRejected(this.reason);
              resolvePromise(promise2, x, resolve, reject);
            } catch (error) {
              reject(error);
            }
          });
        };
        if (this.status === FULFILLED) {
          microtaskFulfilled();
        } else if (this.status === REJECTED) {
          microtaskRejected();
        } else {
          this.resolveCallbackList.push(microtaskFulfilled);
          this.rejectCallbackList.push(microtaskRejected);
        }
      });

      return promise2;
    }

    catch(onRejected) {
      this.then(null, onRejected);
    }

    static resolve(value) {
      return new MyPromise((resolve) => {
        resolve(value);
      });
    }

    static reject(reason) {
      return new MyPromise((resolve, reject) => {
        reject(reason);
      });
    }

    static race(list: MyPromise[]) {
      return new MyPromise((resolve, reject) => {
        for (let i = 0; i < list.length; i++) {
          list[i]
            .then((val) => {
              resolve(val);
            })
            .catch((err) => {
              reject(err);
            });
        }
      });
    }

    static all(list: MyPromise[]) {
      const resList = [];
      let count = 0;
      return new MyPromise((resolve, reject) => {
        for (let i = 0; i < list.length; i++) {
          list[i]
            .then((val) => {
              count++;
              resList.push(val);
              if (count === list.length) {
                resolve(resList);
              }
            })
            .catch((err) => {
              reject(err);
            });
        }
      });
    }
  }

  const p1 = new MyPromise((resolve) => {
    resolve(111);
  }).then((val) => {
    console.log(val);
    return 222;
  });

  const p2 = p1
    .then((val) => {
      console.log(val);
      return 333;
    })
    .then((val) => {
      console.log(val);
      return p1;
    })
    .then((val) => {
      console.log(val);
      return 111;
    });

  MyPromise.resolve('你好').then((res) => {
    console.log(res);
  });

  MyPromise.reject('reject').catch((err) => {
    console.log(err);
  });

  const race1 = new MyPromise((resolve) => {
    setTimeout(() => {
      resolve('race1');
    }, 200);
  });

  const race2 = new MyPromise((resolve) => {
    setTimeout(() => {
      resolve('race2');
    }, 500);
  });

  MyPromise.race([race1, race2]).then((val) => {
    console.log(val);
  });

  MyPromise.all([race1, race2]).then((val) => {
    console.log(val);
  });
})();

Async/Await

// async/await
(() => {
  const async = (genertor) => {
    const iterator = genertor();

    function handle(iteratorResult) {
      if (iteratorResult.done) return;
      const itertorValue = iteratorResult.value;
      if (itertorValue instanceof Promise) {
        itertorValue.then((res) => handle(iterator.next(res))).catch((err) => iterator.throw(err));
      }
    }

    try {
      handle(iterator.next());
    } catch (error) {
      iterator.throw(error);
    }
  };

  const fn = (i) => {
    return new Promise((resolve) => {
      setTimeout(() => {
        resolve(++i);
      }, i * 300);
    });
  };

  async(function* () {
    const val1 = yield fn(2);
    console.log(val1);
    const val2 = yield fn(val1);
    console.log(val2);
    const val3 = yield fn(val2);
    console.log(val3);
    return val3;
  });
})();
上次更新:
贡献者: chenzilin