Vue2 核心原理

响应式系统

  • 实现步骤
    • 首先创建了一个新的空对象
    • 设置原型,将对象的原型设置为函数的 prototype 对象。
    • 让函数的 this 指向这个对象,执行构造函数的代码(为这个新对象添加属性)
    • 判断函数的返回值类型,如果是值类型,返回创建的对象。如果是引用类型,就返回这个引用类型的对象。
function myNew(fn, ...args) {
  //创建一个空对象并将对象的原型设置为函数的prototype对象
  const obj = {};
  obj.__proto__ = fn.prototype;
  //以上两步可合成一步
  //const obj = Object.create(fn.prototype)

  //调用构造函数,并且this绑定到obj上
  const value = fn.apply(obj, args);
  // 如果构造函数有返回值,并且返回的是对象,就返回value ;否则返回obj
  return value instanceof Object ? value : obj;
}

模板编译

  • 实现步骤
    • 获取类型的原型
    • 获得对象的原型
    • 一直循环判断对象的原型是否等于类型的原型,直到对象原型为 null,因为原型链最终为 null
//判断构造函数的 prototype 属性是否出现在对象的原型链中的任何位置。
function myInstanceof(left, right) {
  let proto = Object.getPrototypeOf(left), // 获取对象的原型
    prototype = right.prototype; // 获取构造函数的 prototype 对象

  // 判断构造函数的 prototype 对象是否在对象的原型链上
  while (true) {
    if (!proto) return false;
    if (proto === prototype) return true;

    proto = Object.getPrototypeOf(proto);
  }
}

虚拟 DOM

/**
 * @description typeof 可以正确识别:Undefined、Boolean、Number、String、Symbol、Function 等类型的数据,
 * 但是对于其他的都会认为是 object,比如 Null、Date 等,
 * 所以通过 typeof 来判断数据类型会不准确。但是可以使用 Object.prototype.toString 实现。
 */
function typeOf(obj) {
  let type = Object.prototype.toString.call(obj);
  return type.slice(8, -1).toLowerCase();
}
console.log(typeOf(new Date()), typeOf(null), typeOf([]));

组件化

this 指向第一个参数

  • call
    • 传参方式:多个参数
    • 立即执行
  • apply
    • 传参方式:第二个参数为数组或类数组,用数组接收多个参数
    • 立即执行
  • bind
    • 等待执行
// bind 函数实现
Function.prototype.myBind = function (context) {
  // 判断调用对象是否为函数
  if (typeof this !== "function") {
    throw new TypeError("Error");
  }
  // 获取参数
  var args = [...arguments].slice(1),
    fn = this;
  return function Fn() {
    // 根据调用方式,传入不同绑定值
    return fn.apply(
      this instanceof Fn ? this : context,
      args.concat(...arguments)
    );
  };
};
// call函数实现
Function.prototype.myCall = function (context) {
  // 判断调用对象
  if (typeof this !== "function") {
    console.error("type error");
  }
  // 获取参数
  let args = [...arguments].slice(1),
    result = null;
  // 判断 context 是否传入,如果未传入则设置为 window
  context = context || window;
  // 将调用函数设为对象的方法
  context.fn = this;
  // 调用函数
  result = context.fn(...args);
  // 将属性删除
  delete context.fn;
  return result;
};
// apply 函数实现
Function.prototype.myApply = function (context) {
  // 判断调用对象是否为函数
  if (typeof this !== "function") {
    throw new TypeError("Error");
  }
  let result = null;
  // 判断 context 是否存在,如果未传入则为 window
  context = context || window;
  // 将函数设为对象的方法
  context.fn = this;
  // 调用方法
  result = arguments[1] ? context.fn(...arguments[1]) : context.fn();

  // 将属性删除
  delete context.fn;
  return result;
};
上次更新:
贡献者: Chris-Wen