【Vue的响应式原理】


一、Vue2

1.基本原理

在vue2中利用的是原生js下的Obiect.defineProperty()进行数据劫持,在通过里面的gettersetter方法,进行查看和数据的修改,通过发布、订阅者模式进行数据与视图的响应式

2.定义初始数据

在这里插入图片描述
在这里插入图片描述

3.加工数据

为了实现响应式,在js中Object.defineProperty()给每个初始数据都形成了get和set的写法,只要读取数据就会执行get方法,编辑数据执行set方法。

(1)响应式数据

在这里插入图片描述

(2)get查看age属性,执行get

在这里插入图片描述
在这里插入图片描述

(3)set修改数据的时候调用set

在这里插入图片描述
在这里插入图片描述

(4)总结

当数据发生变化时,触发响应的监听回调(get/set),就已经实现了数据的双向绑定

4.vue双向绑定的缺点

(1)不能监听对象的新增属性和删除
(2)无法正确的监听数组的方法,当监听下标对应的数据发生变化时

5.解决办法

(1)重写数组或对象
(2)vue中通过this.$set(目前属性,新增的属性,新增的值)来解决

二、Vue3

1.基本原理

(1)对于基本数据类型来说,响应式依然是靠Object.defineProperty()的get和set来完成的
(2)对于对象类型数据:

  • 通过Proxy代理,拦截对象中任意属性的变化,包括属性值的读写、添加、删除等
  • 通过Reflect反射函数进行操作
    Vue3中响应式是通过函数来实现的

2.ref函数

(1)作用:定义一个响应式数据
(2)语法:let xxx=ref(xxx)
在这里插入图片描述

(3)创建一个包含响应式数据的引用对象
(4)js中操作数据:xxx.value
在这里插入图片描述
(5)模板中读取数据:不需要.value直接使用插值语法即可
(6)注:接收的数据可以是基本类型也可以是对象类型

3.reactive函数

(1)作用:定义一个对象类型的响应式数据
(2)语法:const xxx=reactive(源对象)接收一个数组或者对象,返回一个Proxy的实例对象,简称Proxy
在这里插入图片描述
返回proxy对象在这里插入图片描述

(3)reactive定义的响应式的数据是深层次的
(4)接受的是数组,通过索引改变的数据也是响应式的

三、Vue的响应式原理基于的核心概念:

(1)Observer:Vue使用Observer来监控数据的变化,一旦数据变化,就触发视图更新。
(2)Dep:每个数据属性都有一个Wep依赖管理器,它记录依赖于这个属性的所有Watcher。
(3)Watcher:每个组件实例都有相应的Watcher,它会在组件渲染过程中“观察”数据的变化。
(4)Virtual DOM:Vue使用Virtual DOM来高效地更新DOM。
(5) Diff算法 当数据变化时,新旧Virtual DOM会进行Diff算法对比差异,然后只更新有差异的部分

// 假设的Vue响应式核心代码
class Vue {
  constructor(options) {
    this._data = options.data;
    observe(this._data, this); // 监控数据
    new Compiler(options.el, this); // 编译模板,并生成Watcher
  }
}
 
function observe(data, vm) {
  if (!data || typeof data !== 'object') {
    return;
  }
  Object.keys(data).forEach(key => {
    defineReactive(data, key, data[key], vm); // 对每个数据属性进行响应式处理
  });
}
 
function defineReactive(obj, key, val, vm) {
  const dep = new Dep();
  
  // 获取属性的Descriptor
  const property = Object.getOwnPropertyDescriptor(obj, key);
  if (property && property.configurable === false) {
    return;
  }
 
  // 使用getter和setter重写属性
  Object.defineProperty(obj, key, {
    enumerable: true,
    configurable: true,
    get: function reactiveGetter() {
      dep.addSub(Dep.target); // 添加依赖
      return val;
    },
    set: function reactiveSetter(newVal) {
      if (val === newVal) return;
      val = newVal;
      dep.notify(); // 通知依赖更新
    }
  });
}
 
class Dep {
  constructor() {
    this.subs = [];
  }
  
  addSub(sub) {
    this.subs.push(sub);
  }
  
  notify() {
    this.subs.forEach(sub => {
      sub.update(); // 执行更新操作
    });
  }
}
 
// 假设的Watcher类
class Watcher {
  constructor(vm, expOrFn, cb) {
    this.vm = vm;
    this.expOrFn = expOrFn;
    this.cb = cb;
    this.value = this.get(); // 获取初始值,同时订阅依赖
  }
  
  get() {
    Dep.target = this; // 设置当前Watcher为target
    const value = this.vm._data[this.expOrFn]; // 触发属性的getter
    Dep.target = null; // 重置
    return value;
  }
  
  update() {
    const newValue = this.vm._data[this.expOrFn];
    if (newValue !== this.value) {
      this.cb.call(this.vm, newValue); // 执行更新回调
    }
  }
}
 
// 假设的Compiler类
class Compiler {
  constructor(el, vm) {
    this.el = document.querySelector(el);
    this.vm = vm;
    if (this.el) {
      const fragment = this.nodeToFragment(this.el);
      this.compile(fragment);
      this.el.appendChild(fragment);
    }
  }
  
  nodeToFragment(el) {
    // 将DOM转换为Fragment的实现
  }
  
  compile(fragment) {
   
  • 17
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值