Skip to content

vue3响应系统

  • 读《vue.js的设计与实现》 霍春阳

Vue.js 3 采用 Proxy 实现响应式数据, 取代 vue2中的 Object.defineProperty

1. 响应式数据与副作用函数

副作用函数指的是会产生副作用的函数
js
const obj = {
  text: 'hello vue'
}
const effect = () => {
  document.body.innerText = obj.text
}

effect 函数的执行会直接或间接影响其他函数的执行,这时我们说 effect 函数产生了副作用副作用很容易产生,例如一个函数修改了全局变量,这其实也是一个副作用,如上面的代码所示

响应式数据
js
obj.text = 'hello  vue3'

这句代码修改了字段 obj.text 的值,我们希望当值变化后,副作用函数自动重新执行,如果能实现这个目标,那么对象 obj 就是响应式数据

那么如何让数据,变成响应式数据?

vue2 使用 Object.defineProperty

Object.defineProperty()‌ 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。

Object.defineProperty(obj, prop, descriptor)
  • obj‌: 目标对象
  • ‌prop‌: 属性名(字符串或Symbol)
  • ‌descriptor‌: 属性描述符对象,包含以下可选键值:‌‌
    • value: 属性值
    • writable: 是否可写
    • enumerable: 是否可枚举
    • configurable: 是否可配置
    • get: getter函数,用于获取属性值
    • set: setter函数,用于设置属性值
通过get/set拦截属性访问

Vue2 的响应式原理即基于此:

js
const obj1 = {}

Object.defineProperty(obj1, 'name', {
  value: '张三',
  get() {
    return this.value + '??'
  },
  set(newVal) {
    this.value = newVal
    document.body.innerText = this.value
  },
})

console.log(obj1.name)  //张三?? 

obj1.name = '李四'
console.log(obj1.name)  //李四??

Vue.js 3 采用 Proxy

Proxy 对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)。

const p = new Proxy(target, handler)
  • target: 目标对象
  • handler: 一个对象,其属性是当执行一个操作时定义代理的行为的函数
    • get
    • set
基础使用
js
//定义一个需要代理的对象
let person = {
  age: 0,
  name: '张三'
}

// 定义代理
let proxyObj = new Proxy(person, {
  /**
   * obj 目标对象
   * key 属性名
   */
  get(obj, key) {
    console.log('触发了get')
    // 如果对象里有这个属性,就返回属性值,如果没有,就返回默认值66
    return key in obj ? obj[key] : '无此值'
  },
  /**
   * obj 目标对象
   * key 属性名
   * val 属性值
   */
  set(obj, key, val) {
    console.log('触发了set')
    obj[key] = val
    return true
   }
})

console.log(proxyObj.name)  //张三
console.log(proxyObj.age)  //0
console.log(proxyObj.test)  //无此值

可以看出,Proxy代理的是整个对象,而不是对象的某个特定属性,不需要我们通过遍历来逐个进行数据绑定。

京ICP备2024093538号-1