js手写记录

42 阅读2分钟

实现千分位分隔符

const str = '12345678.12345678';
const split = (str: string) => {
  const flag = /^\d+(.\d+)?$/.test(str);
  if (!flag) {
    throw new Error("请输入合法的参数!");
  }

  const arr = str.split('.'); // str.match(/^(\d+)(?:.(\d+))?$/)
  let ans: string[] = [];
  arr.forEach(item => {
    const a = item.replace(/(?=(\B\d{3})+$)/g, ',');
    ans.push(a);
  })
  return ans.join('.');
}

console.log(split(str));

获取url中的参数

const url = 'https://cn.bing.com/search?pglt=41&q=call+apply+bind&cvid=b169708dd90e40c48c8f16c2cf4eec08&gs_lcrp=EgRlZGdlKgYIARAAGEAyBggAEEUYOTIGCAEQABhAMgYIAhAAGEAyBggDEAAYQDIGCAQQABhAMgYIBRAAGEAyBggGEAAYQDIGCAcQABhAMgYICBAAGEDSAQg0MTEzajBqMagCALACAA&FORM=ANNTA1&PC=U531'
const getPramas = (url: string, key?: string) => {
  if (!key) {
    const params: { [key: string]: string } = {};
    const keys: any = url.match(/[^?&]+(?==)/g);
    const values: any = url.match(/(?<==)[^&]+/g);
    for (let index in keys) {
      params[keys[index]] = values[index];
    }
    return params;
  }
  else {
    // 获取单个参数
    const reg = new RegExp(`(?<=\?|&)${key}=(.+?)(?=&|$)`);
    const res = url.match(reg);

    if (!res) {
      throw new Error('未匹配到相应的参数');
    }
    return res[1];
  }
}

const arr = getPramas(url);
const res = getPramas(url, 'q');
console.log(arr, res);

发布订阅模式

class EventEmmit {
  public arr: any = {};
  constructor() {
    this.arr = {};
  }

  on(name: any, callback: any) {
    if (!this.arr[name]) {
      this.arr[name] = [];
    }

    this.arr[name].push(callback);
  }

  off(name: any, fn: any) {
    if (!this.arr[name]) {
      return;
    }

    const idx = this.arr[name].findIndex((item: any) => item === fn);
    this.arr[name].splice(idx, 1);
  }

  emit(name: any, once: boolean = false, ...props: any) {
    if (!this.arr[name]) {
      console.log('没有监听!');
      return;
    };

    this.arr[name].forEach((fun: any) => fun(...props));
    if (once) {
      delete this.arr[name];
    }
  }
}

const a = new EventEmmit();

const add = (a: any, b: any) => {
  console.log(a + b);
}

a.on('test', (a: any, b: any) => {
  console.log(a, b);
})

a.on('test', add);
console.log('---------------------------------------------- notice1');
a.emit('test', undefined, 1, 2);
a.off('test', add);
console.log('---------------------------------------------- notice1');
a.emit('test', undefined, 1, 2);

a.on('test2', (a: any, b: any, c: any) => {
  console.log(a, b, c);
})


console.log('---------------------------------------------- notice1');
a.emit('test', undefined, 1, 2);
console.log('---------------------------------------------- notice1');
a.emit('test2', true, 1, 2, 3);
console.log('---------------------------------------------- notice2');
a.emit('test', undefined, 1, 2);
console.log('---------------------------------------------- notice2');
a.emit('test2', true, 1, 2, 3);

instanceof

const myInstance = (obj: any, type: any) => {
  if (typeof obj !== 'object' && typeof obj !== 'function' && obj === null) {
    return false;
  }

  let proto = Object.getPrototypeOf(obj);
  while (true) {
    if (proto === null) {
      return false;
    }
    if (proto === type.prototype) {
      return true;
    }
    proto = Object.getPrototypeOf(proto);
  }
}

const obj = {};
const res = myInstance(obj, Object);
console.log(res);

image.png

深拷贝

完整版基本上覆盖了所有类型,如基本类型、set、map、Symbol、RegExp、Function等等。实际上只需书写部分就好。

初始化关键。

const getType = (obj: any) => Object.prototype.toString.call(obj);

const isObject = (target: any) => (typeof target === 'object' || typeof target === 'function') && target !== null;

const canTraverse: any = {
  '[object Map]': true,
  '[object Set]': true,
  '[object Array]': true,
  '[object Object]': true,
  '[object Arguments]': true,
};
const mapTag = '[object Map]';
const setTag = '[object Set]';
const boolTag = '[object Boolean]';
const numberTag = '[object Number]';
const stringTag = '[object String]';
const symbolTag = '[object Symbol]';
const dateTag = '[object Date]';
const errorTag = '[object Error]';
const regexpTag = '[object RegExp]';
const funcTag = '[object Function]';

const handleRegExp = (target: any) => {
  const { source, flags } = target;
  return new target.constructor(source, flags);
}

const handleFunc = (func: any) => {
  // 箭头函数直接返回自身
  if (!func.prototype) return func;

  const bodyReg = /(?<={)(.|\n)+(?=})/m;
  const paramReg = /(?<=()(.+)(?=)\s*{)/;
  const funcString = func.toString();
  // 分别匹配 函数参数 和 函数体
  const param = paramReg.exec(funcString);
  const body = bodyReg.exec(funcString);
  if (!body) return null;
  if (param) {
    const paramArr = param[0].split(',');
    return new Function(...paramArr, body[0]);
  } else {
    return new Function(body[0]);
  }
}

const handleNotTraverse = (target: any, tag: any) => {
  const Ctor = target.constructor;
  switch (tag) {
    case boolTag:
      return new Object(Boolean.prototype.valueOf.call(target));
    case numberTag:
      return new Object(Number.prototype.valueOf.call(target));
    case stringTag:
      return new Object(String.prototype.valueOf.call(target));
    case symbolTag:
      return new Object(Symbol.prototype.valueOf.call(target));
    case errorTag:
    case dateTag:
      return new Ctor(target);
    case regexpTag:
      return handleRegExp(target);
    case funcTag:
      return handleFunc(target);
    default:
      return new Ctor(target);
  }
}

const deepClone = (target: any, map = new WeakMap()) => {
  if (!isObject(target))
    return target;
  let type = getType(target);
  let cloneTarget;
  if (!canTraverse[type]) {
    return handleNotTraverse(target, type);
  } else {
    const ctor = target.constructor;
    cloneTarget = new ctor();
  }

  if (map.get(target))
    return map.get(target);
  map.set(target, cloneTarget);

  if (type === mapTag) {
    target.forEach((value: any, key: any) => {
      cloneTarget.set(deepClone(key, map), deepClone(value, map))
    })
  }

  if (type === setTag) {
    target.forEach((value: any) => {
      cloneTarget.add(deepClone(value, map));
    })
  }

  for (let key in target) {
    if (target.hasOwnProperty(key)) {
      cloneTarget[key] = deepClone(target[key], map);
    }
  }

  return cloneTarget;
}

const obj1: any = {
  name: '对象1',
  nested: null
};

const obj2: any = {
  name: '对象2',
  nested: obj1
};

obj1.nested = obj2;

const a = deepClone(obj1);
a.nested.nested.nested = 11;
console.log(obj1);

实现new

一共三步

  • 初始化一个object类型
  • obj.proto = Con.prototype
  • 执行Con
function createObject(Con) {
  // 创建新对象obj
  // let obj = {};也可以
  let obj = Object.create(null);

  // 将obj.__proto__ -> 构造函数原型
  // (不推荐)obj.__proto__ = Con.prototype
  Object.setPrototypeOf(obj, Con.prototype);

  // 执行构造函数,并接受构造函数返回值
  const ret = Con.apply(obj, [].slice.call(arguments, 1));

  // 若构造函数返回值为对象,直接返回该对象
  // 否则返回obj
  return typeof(ret) === 'object' ? ret: obj;
}

防抖和节流

const debounce = (callback: any, time: number) => {
  let timer: any = null;

  return () => {
    clearTimeout(timer);
    timer = setTimeout(() => {
      callback();
      timer = null;
    }, time);
  }
};
const throttle = (callback: any, time: number) => {
  let timer: any = null;

  return () => {
    if (timer) {
      return;
    }

    timer = setTimeout(() => {
      callback();
      timer = null;
    }, time);
  }
}