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