vue2和vue3的响应式原理

44 阅读3分钟

vue2的响应式原理

  • 实现原理:

     对象类型:通过Object.defineProperty() 对属性读取,修改进行拦截(数据劫持)
     数组类型: 通过重写更新数组的一系列方法来实现拦截 ( 对数组的变更方法进行了包裹)
    
  • 存在问题:

       新增属性,删除属性,界面不会更新
       直接通过下标修改数组,界面不会自动更新
    
  • 在vue2 中解决的方法:

对象追加属性:

this.$set(对象,添加的属性,添加的值)
或者引入import Vue from 'vue'
Vue.set(对象,添加的属性,添加的值)

对象删除属性:

this.$delete(对象,属性名)
或者引入import Vue from 'vue'
Vue.delete(对象,添加的属性,添加的值)

数组修改元素:

this.$set(对象,数组下标,值)
this.数组.splice(起始位置,第几个元素,修改的名)

数组删除元素:

this.数组.splice(起始位置,0)

模拟vue2 中的响应式原理

Object.defineProperty

Object.defineProperty( objpropdescriptor )

  obj : 要定义属性的对象。

  prop : 要定义或修改的属性的名称或 Symbol 。

  descriptor : 要定义或修改的属性描述符

let person={
  name:'xwxw',
  age:18
}
let p={}

for(let k in person){
  Object.defineProperty(p,k,{
  // 表示可以删除
  configurable:true,
  get(){
    return person[k];
  },
  set(value){
    person[k]=value;
  }
})
}

vue3 响应式原理

  • 实现原理

    • 通过Proxy(代理): 拦截对象中的任意属性的变化,包括:属性值的读写,属性的添加,属性的删除等.
    • 通过Reflect(反射): 对杯代理对象的属性进行操作

模拟vue3 响应式原理

反射机制

Reflect 是一个内建的对象,用来提供方法去拦截 JavaScript 的操作。

handler ⽅法默认调⽤功能
getReflect.get()获取对象身上某个属性的值
setReflect.set()在对象上设置属性
hasReflect.has()判断一个对象是否存在某个属性
deletePropertyReflect.deleteProperty()删除对象上的属性
getPropertyReflect.getPrototypeOf()获取指定对象原型的函数
setPropertyReflect.setPrototypeOf()设置或改变对象原型的函数
isExtensibleReflect.isExtensible()判断一个对象是否可扩展 (即是否能够添加新的属性)
preventExtensionsReflect.preventExtensions()阻止新属性添加到对象
getOwnPropertyDescriptorReflect.getOwnPropertyDescriptor()获取给定属性的属性描述符
definePropertyReflect.defineProperty()定义或修改一个对象的属性
ownKeysReflect.ownKeys()返回由目标对象自身的属性键组成的数组
applyReflect.apply()对一个函数进行调用操作,同时可以传入一个数组作为调用参数
constructReflect.construct()对构造函数进行 new 操作,实现创建类的实例
.preventExtensionsReflect.preventExtensions()阻止新属性添加到对象

代理对象

Proxy是js中的原生对象,用来创建一个对象的代理,可以实现基本操作的拦截和自定义

new Proxy(target, handler)

  • target是要代理的对象

  • handler中定义了基本操作的逻辑

let person={
  name:'xwxw',
  age:18
}
const p= new Proxy(person,{
  // target 表示的person对象, propName 代表的是读取的属性名
  get(target,propName){
    return Reflect.get(target,propName)
  },
  set(target,propName,value){
    Reflect.set(target,propName,value)
  },
  deleteProperty(target,propName){
   return Reflect.deleteProperty(target,propName)
  }
})

vue3中 reactive对比ref

  • 从定义数据的角度对比:

    • ref用来定义:基本数据类型
    • reactlve用来定义:对象(或数组)类型数据
    • ref也可以用来定义对象或数组数据类型,他内部会自动通过reactive转为代理对象
  • 从原理角度对比:

    • ref通过Object.defineProperty()getset来实现响应式(数据劫持)
    • reactive通过使用Proxy来实现响应式(数据劫持),并通过Reflect操作源对象内部的数据
  • 从使用角度对比:

    • ref定义的数据:操作数据需要.value,读取数据时模板中不需要.value
    • reactive定义的数据: 操作与读取数据都不需要.value