vue中响应式数据的实现以及reactive、ref、toRef、toRefs的区别

目录

一、vue2通过 Object.defineProperty

二、vue3通过 Proxy

三、reactive、ref、toRef、toRefs的区别


一、vue2通过 Object.defineProperty 

1.1、对单个属性进行监听

var obj={
    a:1,
    b:'字符串b'
}
var obj2

Object.defineProperty(obj,'a',{
    get:()=>{
        console.log('触发get')
        return 'aaa'
    },
    set:(v)=>{
        console.log("触发set")
        obj2=v
    }
})
console.log('obj2初始:',obj2)   // obj2初始: undefined
obj.a                          // 触发get
obj.a = 3                      // 触发set,
console.log('obj2现:',obj2)     // obj2现: 3
console.log('obj.a:',obj.a)     //触发get   obj.a: aaa     //set中无返回值,所以obj.a = 3 本质是对obj2 进行赋值

1.2、对对象进行监听

  想对obj对象进行赋值的时候,要小心出现死循环。


var obj={
    a:1,
    b:'字符串b'
}
var obj2

Object.keys(obj).forEach(k=>{
    Object.defineProperty(obj,k,{
    get:()=>{
        console.log('触发get')
        return 'aaa'
    },
    set:(v)=>{
        console.log("触发set")
        return obj[k]=v   
    }
})
})

obj.b = 'ss'   //结果会重复打印“触发set” --由于set中也调用了 obj的set方法,相当于递归,会形成死循环

  改进 避免在set 或get方法实现递归,可以在外部进行定义

var obj={
    a:1,
    b:'字符串b',
    c:[],
    d:{
        name:'eee'
    }
}

function definePropertyFun(data,key,val){
    if(Object.prototype.toString.call(val)==='[object Object]'){
        observer(val)
        return 
    }
    Object.defineProperty(data,key,{
    get:()=>{
        console.log('触发get')
        return val
    },
    set:(v)=>{
        console.log("触发set")
        return val=v
    }
})
}

function observer(data){
    if(Object.prototype.toString.call(data) !=='[object Object]'){
        console.log('传参要是对象类型')
        return 
    }

    Object.keys(data).forEach( k => {
        definePropertyFun(data,k,data[k])
    })
}

observer(obj)   //对对象进行监听
obj.a=5         // 触发set
console.log(obj.a);  // 触发get   5

obj.c = [0,1]   // 触发set
obj.c[1]=2      // 触发get      无法触发 set ,vue2中也无法触发set
obj.c.push(3)   // 触发get      vue2可以触发set,它对push进行了重写

obj.d.name = 's' // 触发set

二、vue3通过 Proxy

vue3的实现方式更加优雅

var obj={
    a:1,
    b:'字符串b',
    c:[],
    d:{
        name:'eee'
    }
}
var obj2='d'

const newobj = new Proxy(obj,{
    get:(data,val)=>{
        console.log('触发get')
        return data[val]
    },
    set:(data,key,val)=>{
        console.log("触发set")
        return data[key]=val  
    }

})

newobj.a           //触发get 
newobj.c.push(3)   //触发get   
newobj.d.name      //触发get    
newobj.p="ds"      //触发set   原本不存在的属性也可以

三、reactive、ref、toRef、toRefs的区别

官方文档:Refs | Vue.js

接受 返回
reactive 对象类型 响应式对象(proxy对象)
ref

基本数据类型

(若是对象类型,将调用reactive函数)

扫描二维码关注公众号,回复: 14894782 查看本文章
返回一个响应式且可变的 ref 对象,有一个 .value 属性

toRef 和 toRefs

相同:

  • toRef 和 toRefs 是将响应式对象中的属性也转换为响应式的。
  • 不丢失对源对象的响应式链接,即修改源对象属性值,生成的新对象的对应属性值(ref)也会修改,反之亦然。

区别:

  • toRef:接受两个参数,源对象 和 属性名 ,返回 一个ref数据
  • toRefs:一次将所有属性都转为响应式的。常用于响应式对象的解构

注意

如果只是对数据进行ref操作,则得到的是数据拷贝,改变结果数据的值不会改变源对象的值,而经过 toRef或toRefs 得到的才是数据得引用

猜你喜欢

转载自blog.csdn.net/qq_41045128/article/details/125944134
今日推荐