浅谈vue2和vue3之间的响应式原理

既然vue2和vue3都是基于vue的,为什么底层会一直改变,原本不想学习vue3的,觉得够用就行,但是有时候在vue2的项目中却会发现一种难以言语的不便

比如你不可能直接的去修改或者删除某个对象的属性或者值,尽管你可以通过set方法去修改,但是为什么不能修改呢,本质是数据虽然修改了但是页面还是呈现不出来呢?

~所以,前端搬运工还是要往前继续走,继续踩

 

模拟vue2的响应式原理

回顾一下Object.defineProperty()这是啥,我们去MDN走一趟----

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty

得到的解释是 ----

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

语法----

Object.defineProperty(obj, prop, descriptor)

传值---

configurable
当且仅当该属性的 configurable 键值为 true 时,该属性的描述符才能够被改变,同时该属性也能从对应的对象上被删除。
默认为 false
enumerable
当且仅当该属性的 enumerable 键值为 true 时,该属性才会出现在对象的枚举属性中。
默认为 false

数据描述符还具有以下可选键值:

value
该属性对应的值。可以是任何有效的 JavaScript 值(数值,对象,函数等)。
默认为 undefined
writable
当且仅当该属性的 writable 键值为 true 时,属性的值,也就是上面的 value,才能被赋值运算符 (en-US)改变。
默认为 false

存取描述符还具有以下可选键值:

get
属性的 getter 函数,如果没有 getter,则为 undefined。当访问该属性时,会调用此函数。执行时不传入任何参数,但是会传入 this 对象(由于继承关系,这里的this并不一定是定义该属性的对象)。该函数的返回值会被用作属性的值。
默认为 undefined
set
属性的 setter 函数,如果没有 setter,则为 undefined。当属性值被修改时,会调用此函数。该方法接受一个参数(也就是被赋予的新值),会传入赋值时的 this 对象。
默认为 undefined

通过下面的案例想想vue2的响应式原理以及数据劫持是如何的,顺便再想想vue.js的的设计模式--发布者-订阅者,可以去玩一下pubsub.js 这里只是浅谈一下响应式原理

 //初数据
let person = {
name:'张大标',
age:90
}

let p = {}
Object.defineProperty(p,'name',{
configurable:true,
get(){ 
return person.name
},
set(value){ 
person.name = value
}
})
Object.defineProperty(p,'age',{
get(){
return person.age
},
set(value){
person.age = value
}
}) 

 

模拟vue3的响应式原理

 

我们先了解一下Proxy --- 代理

定义---

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

参数---

target
要使用 Proxy 包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)。
handler
一个通常以函数作为属性的对象,各属性中的函数分别定义了在执行各种操作时代理 p 的行为。

那么p如何去映射person呢?那是不是直接联想到数据劫持?

const p = new Proxy(person,{
get(target,property){
return Reflect.get(target,property)
},
set(target,property,value){
Reflect.set(target,property,value)
},
deleteProperty(target,property){  //最关键的是这里,捕获数据的改变做响应式
return Reflect.deleteProperty(target,property)   //   如果这里不明白,接着看.......--->>>>
}
})

 

再来引入下为什么要用Reflect --- 映射  

Reflect 是一个内置的对象,它提供拦截 JavaScript 操作的方法。这些方法与proxy handlers (en-US)的方法相同。Reflect不是一个函数对象,因此它是不可构造的。

一个简单的reflect的例子-----

     读操作----

 

 

     写操作---

    

 

     删除操作---

 

 

 似乎你会觉得操作对象不需要用到reflect,但是reflec正在被ECMA在Object的大量API移植到其身上,如下文档----->

   https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Reflect

 

 -----结束

posted @ 2022-04-13 21:49  ROSE-YE  阅读(268)  评论(0)    收藏  举报