Skip to content

手写代码

声明

整个知识库涉及的资料一部分为自主收集整理,一部分来源于网络收集,如有侵权请联系我

手写 new 操作符

new 操作符在 JavaScript 中用于创建一个用户定义的对象类型的实例。它的工作步骤如下:

  1. 首先创建了一个新的空对象
  2. 设置原型,将对象的原型设置为函数的 prototype 对象。
  3. 让函数的 this 指向这个对象,执行构造函数的代码(为这个新对象添加属性)
  4. 判断函数的返回值类型,如果是值类型,返回创建的对象。如果是引用类型,就返回这个引用类型的对象。
javascript
function myNew(obj, ...args) {
  // 1. 创建一个新的空对象
  // 2. 将这个新对象的原型指向构造函数的 prototype 属性
  const newObject = Object.create(obj.prototype)

  // 3. 将构造函数内部的 this 绑定到这个新对象上,并执行构造函数的代码
  const result = obj.apply(newObject, args);

  // 4. 如果构造函数返回一个对象,则返回该对象;否则,返回新创建的对象
  return result instanceof Object ? result : obj;
}

手写 call 函数

call 函数的实现原理步骤如下:

  1. 判断调用对象是否为函数,即使是定义在函数的原型上的,但是可能出现使用 call 等方式调用的情况。
  2. 判断传入上下文对象是否存在,如果不存在,则设置为 window。
  3. 处理传入的参数,截取第一个参数后的所有参数。
  4. 将函数作为上下文对象的一个属性。
  5. 使用上下文对象来调用这个方法,并保存返回结果。
  6. 删除刚才新增的属性。
  7. 返回结果。
javascript
Function.prototype.myCall = function(context) {
  // 1. 判断调用对象是否为函数
  if (typeof this !== 'function') {
    throw new TypeError('Error');
  }

  // 2. 判断上下文对象是否存在,不存在则设置为window
  context = context || window;

  // 3. 处理传入的参数,截取第一个参数后的所有参数
  const args = [...arguments].slice(1)

  // 4. 将函数设为对象的属性
  // 用Symbol是为了避免属性名冲突
  const fn = Symbol();
  context[fn] = this;

  // 5. 调用函数并传入参数
  const result = context[fn](...args);

  // 6. 删除该属性
  delete context[fn];

  // 7. 返回结果
  return result;
}

手写 apply 函数

apply 函数的实现原理步骤如下:

  1. 判断调用对象是否为函数,即使是定义在函数的原型上的,但是可能出现使用 apply 等方式调用的情况。
  2. 判断传入上下文对象是否存在,如果不存在,则设置为 window。
  3. 将函数作为上下文对象的一个属性。
  4. 判断参数值是否传入。
  5. 使用上下文对象来调用这个方法,并保存返回结果。
  6. 删除刚才新增的属性。
  7. 返回结果。
javascript
Function.prototype.myApply = function(context) {
  // 1. 判断调用对象是否为函数
  if (typeof this !== 'function') {
    throw new TypeError('Error');
  }

  // 2. 判断上下文对象是否存在,不存在则设置为window
  context = context || window;

  // 3. 将函数设为对象的属性
  // 用Symbol是为了避免属性名冲突
  const fn = Symbol();
  context[fn] = this;

  // 4. 调用函数并传入参数
  // 5. 使用上下文对象来调用这个方法
  const result = arguments[1] ? context[fn](...arguments[1]) : context[fn]();

  // 6. 删除该属性
  delete context[fn];

  // 7. 返回结果
  return result;
}

手写 bind 函数

bind 函数的实现原理步骤如下:

  1. 判断调用对象是否为函数,即使是定义在函数的原型上的,但是可能出现使用 bind 等方式调用的情况。
  2. 保存当前函数的引用,获取其余传入参数值。
  3. 创建一个函数返回
  4. 函数内部使用 apply 来绑定函数调用,需要判断函数作为构造函数的情况,这个时候需要传入当前函数的 this 给 apply 调用,其余情况都传入指定的上下文对象。
javascript
Function.prototype.myBind = function(context) {
  // 1. 判断调用对象是否为函数
  if (typeof this !== 'function') {
    throw new TypeError('Error');
  }

  // 2. 保存当前函数的引用,获取其余传入参数值
  const fn = this;
  const args = [...arguments].slice(1);

  // 3. 创建一个返回函数
  return function Fn() {
    // 根据调用方式,传入不同绑定值
    // 当作为构造函数使用,this指向实例,此时结果为true,将绑定函数的this指向该实例
    // 当作为普通函数使用,this指向window,此时结果为false,将绑定函数的this指向context
    return fn.apply(
      this instanceof Fn ? this : context,
      args.concat(...arguments)
    );
  }
}

手写 Promise

javascript
// 定义 Promise 的三种状态
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';

class MyPromise {
  constructor(executor) {
    // 初始化状态
    this.status = PENDING;
    // 存储成功或失败的值
    this.value = undefined;
    // 存储失败的原因
    this.reason = undefined;

    // 存储成功后的回调函数
    this.onFulfilledCallbacks = [];
    // 存储失败后的回调函数
    this.onRejectedCallbacks = [];

    // 定义 resolve 函数
    const resolve = (value) => {
      // 只能由 pending 状态转换为 fulfilled 状态
      if (this.status === PENDING) {
        this.status = FULFILLED;
        this.value = value;
        // 执行成功后的回调函数
        this.onFulfilledCallbacks.forEach(callback => callback(this.value));
      }
    };

    // 定义 reject 函数
    const reject = (reason) => {
      // 只能由 pending 状态转换为 rejected 状态
      if (this.status === PENDING) {
        this.status = REJECTED;
        this.reason = reason;
        // 执行失败后的回调函数
        this.onRejectedCallbacks.forEach(callback => callback(this.reason));
      }
    };

    // 执行 Promise 的 executor 函数
    try {
      executor(resolve, reject);
    } catch (error) {
      reject(error);
    }
  }

  // then 方法
  then(onFulfilled, onRejected) {
    // 如果状态是 fulfilled,立即执行 onFulfilled
    if (this.status === FULFILLED) {
      onFulfilled(this.value);
    }
    // 如果状态是 rejected,立即执行 onRejected
    if (this.status === REJECTED) {
      onRejected(this.reason);
    }

    // 如果状态是 pending,将回调函数添加到对应的队列中
    if (this.status === PENDING) {
      onFulfilled && this.onFulfilledCallbacks.push(onFulfilled);
      onRejected && this.onRejectedCallbacks.push(onRejected);
    }

    // 返回新的 Promise 以实现链式调用
    return this;
  }
}

手写防抖函数

手写节流函数