Skip to content
On this page

new

new 关键字做了什么事

  1. 创建一个新的对象
  2. 将构造函数的原型链赋值到新的对象中
  3. 构造函数中是否返回引用类型的值不是则返回创建的对象

实现

javascript
function myNew(ctx, ...arg) {
  // 1.创建新对象
  let obj = {};
  // 2. 将构造函数的原型链赋值到新的对象中
  obj.__proto__ = ctx.prototype;
  // 3构造函数中是否返回引用类型的值不是则返回创建的对象
  let result = ctx.apply(obj, arg);

  return typeof result === "object" ? result : obj;
}

bind

核心

  1. 返回一个新函数原型链不会被修改
  2. 新函数的 this 关键字绑定到参数的 context 上,且如果没传默认为 window
  3. 函数参数可以在 bind 时绑定,也可以在新函数中绑定
  4. 当新函数当做构造函数时(new) this 指向新函数。

实现

js
Array.prototype.bind = function (context, ...args) {
  const fn = this;

  function tmp(...arg) {
    return fn.apply(this instanceof tmp ? this : context, [...args, ...arg]);
  }

  tmp.prototype = fn.prototype;

  return tmp;
};

Object.create

核心

方法用于创建一个新对象,使用现有的对象来作为新创建对象的原型

实现

js
Object.prototype.create = function (proto) {
  function fn() {}
  fn.prototype = proto;
  fn.constructor = fn;
  return new fn();
};

instanceof

核心

用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上

实现

js
function myInstanceof(left, right) {
  let leftPrototype = Object.getPrototypeOf(left);

  let rightPrototype = right.prototype;

  while (leftPrototype) {
    if (leftPrototype === rightPrototype) {
      return true;
    }
    leftPrototype = Object.getPrototypeOf(leftPrototype);
  }
  return false;
}

深克隆

注意点

这次只实现 dom 节点、循环引用、时间、正则、Map、对象、函数、Set,Symbol 的克隆

实现

js
function isComplex(data) {
  return data && typeof data !== "object" && typeof data !== "symbol";
}

const constructors = [RegExp, Date, Set, Map, WeakMap, WeakSet];

function deepClone(obj, hash = new WeakMap()) {
  if (hash.has(obj)) return hash.get(obj);

  if (constructors.includes(obj.constructor)) {
    return new obj.constructor(obj);
  }

  if (obj instanceof HTMLElement) {
    return obj.cloneNode(true);
  }

  if (typeof obj === "symbol") {
    return Symbol(obj.description);
  }

  if (typeof obj === "function") {
    return new Function(`return ${obj.toString()}`)();
  }

  const desc = Object.getOwnPropertyDescriptors(obj);

  const copy_obj = Object.create(Object.getPrototypeOf(obj), desc);

  for (let key in obj) {
    copy_obj[key] = isComplex(obj[key]) ? deepClone(obj[key], hash) : obj[key];
  }

  return copy_obj;
}

并发限制

核心

利用调度以及开关控制并发数量

实现

es6

js
function p_limit(limit, tasks, callback) {
  const p_tasks = tasks.slice();
  let counter = 0;
  let running = 0;

  let called = 0;
  const result = [];
  function run() {
    if (p_tasks.length && counter <= limit) {
      const task = p_tasks.shift();
      running++;
      task()
        .then((res) => {
          result[called++] = res;
          if (called === counter) {
            callback(result);
          }
        })
        .finally(() => {
          running--;
          run();
        });
      run();
    }
  }

  function push(task) {
    p_tasks.push(task);
    counter++;
  }

  return { run, push };
}

const timeout = (i) => () =>
  new Promise((resolve) => {
    console.log("正在执行i", i);
    setTimeout(() => {
      console.log("准备执行完成i", i);
      resolve(i);
    }, i * 1000);
  });

const { run, push } = limitRequest(
  4,
  [
    timeout(4),
    timeout(1),
    timeout(7),
    timeout(2),
    timeout(3),
    timeout(8),
    timeout(5),

    timeout(9),
    timeout(6),
    timeout(7),
  ],
  (res) => {
    console.log("result", res);
  }
);

run();
push(timeout(11));

ES7 版本

Details
js
function p_limit(limit, tasks, callback) {
  const p_tasks = tasks.slice();

  let counter = p_tasks.length;
  const ret = [];
  const executing = [];
  async function run() {
    for (const task of p_tasks) {
      const p = Promise.resolve().then(() => task());
      ret.push(p);
      if (limit <= counter) {
        const e = p.then(() => executing.splice(executing.indexOf(e), 1));
        executing.push(e);
        if (executing.length >= limit) {
          await Promise.race(executing);
        }
      }
    }
    await Promise.all(ret);
    callback(ret);
  }

  function push(task) {
    p_tasks.push(task);
    counter++;
  }

  return { run, push };
}

洋葱模型

核心

使用 next 来执行下一个函数,可以衍生到 async/await 的自动调用 next Co

实现

js
function compose(middleware) {
  if (!Array.isArray(middleware)) return;

  for (let fn of middleware) {
    if (typeof fn !== "function") {
      return;
    }
  }

  return (context, next) => {
    let index = -1;
    return dispatch(0);

    function dispatch(i) {
      if (i >= middleware.length) return;
      index = i;
      const fn = middleware[i];
      if (i === middleware.length) {
        fn = next;
      }
      if (!fn) return Promise.resolve();
      try {
        return Promise.resolve(fn(context, dispatch.bind(null, i + 1)));
      } catch (e) {
        return Promise.reject(e);
      }
    }
  };
}

防抖

实现

js
function debounce(fn, time, opt={ immediate = false }) {
  let timer = null;
  return function () {
    if (timer) clearTimeout(timer);

    if (opt.immediate) {
      let called = !timer;
      if (called) {
        timer = setTimeout(function () {
          timer = null;
        }, wait);
      } else {
        fn.apply(null);
      }
    } else {
      timer = setTimeout(() => {
        fn.apply(null);
      }, time);
    }
  };
}

节流

实现

js
function throttle(fn, time, opt = { immediate: false }) {
  let timer = null;
  let startTime = Date.now();
  return function () {
    const diff = time - (Date.now() - startTime);
    clearTimeout(timer);
    if (diff > 0) {
      timer = setTimeout(() => {
        fn.apply(null);
        startTime = Date.now();
      }, diff);
    } else {
      fn.apply(null);
      startTime = Date.now();
    }
  };
}

Promise

all

js
const isFunction = (it) => typeof it === "function";

Promise.prototype.all = function (promises) {
  return new Promise((resolve, reject) => {
    let result = [];
    let done = 0;
    for (let i = 0; i < promises.length; i++) {
      const task = promises[i];
      if (isFunction(task)) {
        Promise.resolve()
          .then(() => task())
          .then((res) => {
            result[i] = res;
            done++;
            if (done === promises.length) {
              resolve(result);
            }
          })
          .catch(reject);
      }
    }
  });
};

并发限制

  • 普通版
js
function sendRequest(urls, max, callback) {
  let i = 0;
  const ret = [];
  let finned = 0;
  function request(index) {
    if (finned === urls.length) {
      callback(ret);
      return;
    }
    if (index >= urls.length) {
      return;
    }
    i++;
    const url = urls[index];
    fetch(url)
      .then((res) => {
        ret[index] = res;
      })
      .catch((err) => {
        ret[index] = err;
      })
      .finally(() => {
        request(i++);
        finned++;
      });
  }

  for (let j = 0; j < max; j++) {
    request(j);
  }
}
  • Async/await 版本
js
async function sendRequest(urls, max, callback) {
  async function asyncPool() {
    const ret = [];
    const exec = [];

    for (const url of urls) {
      const p = Promise.resolve().then(() => fetch(url));
      ret.push(p);
      if (urls.length >= max) {
        const t = p.then(() => exec.splice(exec.indexOf(t), 1));
        exec.push(t);
        if (exec.length >= max) {
          await Promise.race(exec);
        }
      }
    }

    return await Promise.all(ret);
  }
  return await asyncPool();
}