目录
一、vue2通过 Object.defineProperty
三、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函数) |
返回一个响应式且可变的 ref 对象,有一个 .value 属性 |
toRef 和 toRefs
相同:
- toRef 和 toRefs 是将响应式对象中的属性也转换为响应式的。
- 不丢失对源对象的响应式链接,即修改源对象属性值,生成的新对象的对应属性值(ref)也会修改,反之亦然。
区别:
- toRef:接受两个参数,源对象 和 属性名 ,返回 一个ref数据
- toRefs:一次将所有属性都转为响应式的。常用于响应式对象的解构
注意:
如果只是对数据进行ref操作,则得到的是数据拷贝,改变结果数据的值不会改变源对象的值,而经过 toRef或toRefs 得到的才是数据得引用