写在前面

Vue3 中的响应式原理以及实现机制,相较于 Vue2 中,有了很大的升级和性能提升。而且优化了很多问题,值得学习和研究!

学习和理解 Vue3 中的响应式原理和实现,对再项目实战中的使用,有很大的帮助;遇到问题时,能发现问题的关键所在。

剖析 Vue2 中是如何实现响应式的

我们知道,在 Vue2 中,Vue 是使用 Object.defineProperty 来实现响应式的。关于 Object.defineProperty,一个简单的例子:

// 源数据
let person = {
  name: '张三',
  age: 18
}

// 模拟 Vue2 中实现响应式
let p = {}
Object.defineProperty(p, 'age', {
  // enumerable:true, // 控制属性是否可以枚举,默认值是false
  // writable:true, // 控制属性是否可以被修改,默认值是false
  // configurable:true, // 控制属性是否可以被删除,默认值是false

  //当有人读取person的age属性时,get函数(getter)就会被调用,且返回值就是age的值
  get(){
	console.log('【检测到了】有人读取age属性了,我可以做一些事情了,这里是响应式的关键')
	return person.number
  },
  //当有人修改person的age属性时,set函数(setter)就会被调用,且会收到修改的具体值
  set(value){
	console.log('【检测到了】有人修改了age属性,且值是:', value)
	person.age = value
  }
})

// ...

上面的例子中,使用了 Object.definePropertypage 属性设置了 setget 方法。

这样,以后,page 属性发生修改或者取值的时候,就能监测到了。

同理,p 中的其他属性,也是这样来实现响应式的,Vue2 中就是这样做的。

Vue2 的响应式存在什么问题?

1、新增属性、删除属性、界面不会更新

Vue2 的解决方法:this.$set(object, 'key', value)this.$delete(object, 'key')

2、直接通过下标修改数组,界面不会自动更新

Vue2 的解决方法:this.$set(object, index, value)

Vue3 响应式

一、ref 函数

在 Vue3 中,定义基本数据类型的响应式,我们使用 ref 函数。

let sum = ref(0)

console.log(sum.value)

return {
  sum
}

ref 函数:

  • 接受的数据可以是:基本类型、也可以是对象类型;
  • 基本类型的数据是:响应式依然是靠 Object.defineProperty()getset 完成的;
  • 对象类型的数据:内部【求助】了 Vue3 中的一个新函数 —— reactive 函数;

二、reactive 函数

定义一个【引用类型】的响应式数据(基本类型不要用它,要用 ref 函数)

let personInfo = reactive({
	name: '张三',
	age: 11,
	jobs: ['前端', '后端', '设计']
})
  • reactive 定义的响应式数据是“深层次的”。
  • 内部基于 ES6 的 Proxy 实现,通过代理对象操作源对象内部数据进行操作。

reactive 响应式原理 - Proxy

  • 通过 Proxy(代理) 拦截对象中任意属性的变化,包括:属性值的读写、属性的添加、属性的删除等。
  • 通过 Reflect(反射)对源对象的属性进行操作。
let proxy = new Proxy(data, {
  // 拦截读取属性值
  get (target, prop) { // target:原对象; prop:读取的属性
    console.log(`监听到了属性值${prop}被读取`)
    return Reflect.get(target, prop)
  },
  // 拦截设置属性值或添加新属性
  set (target, prop, value) { // target:原对象; prop:要修改/增加的属性  value:值
    //target[prop] = value
    console.log(`监听到了属性值${prop}发生变化`)
    return Reflect.set(target, prop, value)
  },
  // 拦截删除属性
  deleteProperty (target, prop) {
    //return delete target[prop]
    console.log(`监听到了属性值${prop}被删除`)
    return Reflect.deleteProperty(target, prop)
  }
})

// proxy 就是源数据 data 的响应式代理对象
proxy.name = 'tom' // 触发监听
let age = proxy.age // 触发监听
delete proxy.name // 触发监听

这种方式实现的响应式,相较于之前的 Object.defineProperty,在代码实现了,简洁优雅了很多。

Proxy 是 ES6 中新提出的方案,也是 JS 语言后面发展的方向,在 JS 语言后续的发展上,如果有改动或者新的提议,也是会在 Proxy 上面来优化,而不太会再优化之前的 Object.defineProperty 方案了。

Vue3 中的响应式解决了 Vue2 中存在的问题

1、新增属性、删除属性、界面会更新了

proxy.page = 1
VM314:15 监听到了属性值page发生变化

新增一个 page 属性时,也会触发 set() 函数了。

2、直接通过下标修改数组,界面也会自动更新

—————————— 【正文完】——————————

前端学习交流群,想进来面基的,可以加群: 832485817685486827
前端顶级学习交流群(一) 前端顶级学习交流群(二)

写在最后: 约定优于配置 —— 软件开发的简约原则

——————————【完】——————————

我的:
个人网站: https://neveryu.github.io/neveryu/
Github: https://github.com/Neveryu
微信: miracle421354532

更多学习资源请关注我的微信…好吗

Logo

前往低代码交流专区

更多推荐