同学:谈谈你对 vue2 响应式原理的理解

开发 前端
Vue 2 的响应式系统通过对象劫持、依赖收集、和更新通知机制来实现数据驱动视图的更新。以下是实现的大致步骤。

Vue 2 的响应式系统通过对象劫持、依赖收集、和更新通知机制来实现数据驱动视图的更新。以下是实现的大致步骤(当然具体的实现复杂得多):

一、对象劫持(Object.defineProperty)

1. 定义响应式对象

使用 Object.defineProperty 对对象的每个属性进行劫持。Vue 2 会为每个属性定义 getter 和 setter,以便在属性被访问或修改时触发相应的逻辑。

function defineReactive(obj, key, val) {
  const dep = new Dep(); // 用于管理依赖

  Object.defineProperty(obj, key, {
    enumerable: true,
    configurable: true,
    get() {
      if (Dep.target) {
        dep.addSub(Dep.target); // 添加当前 watcher 作为依赖
      }
      return val;
    },
    set(newVal) {
      if (newVal === val) return;
      val = newVal;
      dep.notify(); // 通知所有依赖更新
    }
  });
}

2. 递归劫持嵌套对象

如果属性的值是对象,Vue 2 需要递归地将这些对象转化为响应式对象。通过遍历对象的所有属性来实现。

function observe(value) {
  if (!value || typeof value !== 'object') return;
  return new Observer(value);
}

class Observer {
  constructor(value) {
    this.value = value;
    this.walk(value);
  }

  walk(obj) {
    Object.keys(obj).forEach(key => defineReactive(obj, key, obj[key]));
  }
}

二、依赖收集与通知

1. 依赖管理(Dep 类)

Dep 类用于管理所有依赖(即 Watcher 实例)。每当一个属性被访问时,它会将当前 Watcher 实例添加到依赖列表中。当属性值变化时,Dep 会通知所有依赖进行更新。

class Dep {
  constructor() {
    this.subs = [];
  }

  addSub(sub) {
    this.subs.push(sub);
  }

  notify() {
    this.subs.forEach(sub => sub.update());
  }
}

2. Watcher 类

Watcher 类是 Vue 2 响应式系统的核心。它用于接收数据变化通知并更新视图。

class Watcher {
  constructor(updateFn) {
    this.update = updateFn;
    Dep.target = this;
    // 触发 getter 以便收集依赖
    this.value = this.get();
    Dep.target = null;
  }

  get() {
    // 访问数据属性触发 getter
  }

  update() {
    // 数据变化时的处理逻辑
    this.get();
  }
}

三、计算属性与侦听器

、1. 计算属性(Computed Properties)

计算属性是基于响应式数据的缓存值。Vue 2 会自动缓存计算属性的结果,直到它依赖的响应式数据发生变化。

computed: {
  doubledValue() {
    return this.value * 2;
  }
}

在实现上,计算属性会创建一个专门的 Watcher 实例,并在依赖的属性发生变化时重新计算其值。

2. 侦听器(Watchers)

侦听器用于观察数据变化并执行指定的回调函数。

watch: {
  value(newValue, oldValue) {
    // 当 value 发生变化时执行的逻辑
  }
}

四、模板编译

Vue 2 的模板编译过程将模板转换成渲染函数,并利用响应式系统来实现数据驱动的视图更新。渲染函数会访问组件的数据属性,触发依赖收集和视图更新。

function compileTemplate(template) {
  // 编译模板为渲染函数
  return function render() {
    // 渲染逻辑
  };
}

在渲染过程中,模板中的数据绑定会触发属性的 getter,自动收集依赖。当数据变化时,Watcher 会重新计算并更新视图。

五、响应式数据的访问与更新

1. 访问数据

当访问一个响应式属性时,getter 会被触发,当前的 Watcher 会被添加到依赖列表中。

function get() {
  // 访问数据属性触发 getter
  return this.value;
}

2. 更新数据

当设置响应式属性的值时,setter 会被触发,更新数据并通知所有依赖进行更新。

function set(newVal) {
  if (newVal !== this.value) {
    this.value = newVal;
    this.dep.notify(); // 通知所有依赖
  }
}

总结

  • 对象劫持:通过 Object.defineProperty 劫持对象的属性,实现对属性的读写操作的拦截。
  • 递归劫持:递归地将嵌套对象转化为响应式对象。
  • 依赖管理:Dep 类用于管理和通知依赖。
  • 计算属性与侦听器:缓存计算属性,利用侦听器响应数据变化。
  • 模板编译:将模板编译为渲染函数,自动更新视图。

这些细节使 Vue 2 能够高效地实现双向数据绑定和响应式更新,确保视图和数据的一致性。

责任编辑:赵宁宁 来源: 前端历险记
相关推荐

2022-08-26 00:02:03

RocketMQ单体架构MQ

2024-09-20 05:46:00

2024-09-11 16:49:55

2019-07-01 13:34:22

vue系统数据

2022-08-14 07:14:50

Kafka零拷贝

2022-03-29 09:59:58

响应式系统Vue2

2023-11-28 12:25:02

多线程安全

2022-06-30 09:10:33

NoSQLHBaseRedis

2022-09-06 11:13:16

接口PipelineHandler

2022-09-23 11:00:27

KafkaZookeeper机制

2022-04-03 19:27:35

Vue2响应式系统

2022-04-14 08:46:46

响应式系统js

2022-04-02 09:56:41

Vue2响应式系统

2022-04-06 07:28:47

数组响应式系统

2022-08-29 16:03:33

状态流转Java

2022-09-19 07:57:59

云服务互联网基础设施

2022-03-31 10:15:10

分支切换响应式系统

2022-04-10 11:04:40

响应式系统setdelete

2022-10-09 15:18:31

SwaggerOpenAPI工具

2022-04-12 10:05:18

响应式系统异步队列
点赞
收藏

51CTO技术栈公众号