Vue 数据响应式的理解

73 阅读3分钟

什么是vue数据响应式

image.png 数据改变,UI页面做出响应。
当修改 Vue 实例中的 data 属性时,UI页面中的 data 会做出响应,Vue 是通过Object.defineProperty来实现数据响应的。
const vm = new Vue ({data:myDate})

Vue中如何实现数据响应式

1.通过getter和setter修改对象属性实现数据响应

getter:

//修改姓名
let obj3 = {
  姓: "huang",
  名: "rui",
  age: 23,
  get 姓名() {
    return this.姓 + this.名;
  },
  set 姓名(xxx) {
    //设置姓名为obj3.姓名
    this.姓 = xxx[0];
    this.名 = xxx.substring(1);
  }
};
obj3.姓名 = "胡歌";
console.log(`姓名:${obj3.姓}${obj3.名}`);

setter:

let obj3 = {
姓:"高",
名:"圆圆",
get 姓名(){
return this.姓 + this.名;
}
set 姓名(xxx){
 this.姓 = xxx[0]
 this.名 = xxx.substring(1)
}}
obj3.姓名 = "彭于晏"
console.log(`打印三: 姓${obj3.姓},名${obj3.名}`) //打印三:姓:彭,名:于晏

总结: setter就是接受一个参数的函数 用 = xxx 这样的形式触发,来改变里面的值

2.定义完成的对象通过Object.defineProperty(obj,'n',{value:4})添加属性

接上面,我们再使用set和get的时候都是在声明的时候就直接使用的,但是我想声明之后再使用怎么办,这就用到Object.defineProperty()了

Object.defineProperty()第一个参数是告诉它,定义再那个对象上,第二个参数就是要定义个什么东西,然后就能写了

var _xxx = 0
Object.defineProperty(obj3,"xxx",{
 get(){
return _xxx
},
 set(value){
 _xxx = value
}
})

这里需要注意定义的xxx是不存在的所以你用get传是不行的,而且会死循环(因为你在调用xxx的时候就会触发,无限循环),所以需要重新定义一个值用来传。

但是这里有一个问题,我们可以通过直接改变全局变量_xxx来改变里面的值,这不是我们想看到的,那么如何解决这个问题呢?

那就需要一个代理了

let data1 = proxy({data:{n:0}}) // 括号里面是匿名对象,所以根本无法访问

function proxy({data}){
  conost obj = {}
  Object.defineProperty(obj,"n",{
     get(){
 return data.n
}
     set(value){
 if(value<0)return
 data.n = value
}
})
return obj //这就是代理
}

这样你动我obj的n我就会去设置data的n,obj就是一个代理,这样你就不能擅自修改我的对象数据,你只能通过obj代理来修改?

错! 我还是能修改

如果你那个匿名函数我用对象给你呢

let myData5 = {n:0}
let data1 = proxy({data:myData5})

那我只要修改myData5 还是能改你的数据,这时候就不能只靠代理了,还需要监听,就算你改了也没用,我监听你

let myData5 = {n:0}
let data = proxy({data:myData5})

function proxy({data /*这里用了解构赋值*/}){

let value = data.n
delete data.n //这一句可以不写因为下面已经覆盖了原先的n
Object.defineProperty(data,"n",{ //这里挂载的对象就是参数data
     get(){
 return value
}
     set(newvalue){
 if(newvalue<0)return
 value = newvalue
}
})
//上面这几句,就会监听data
  conost obj = {}
  Object.defineProperty(obj,"n",{
     get(){
 return data.n
}
     set(value){
 if(value<0)return
 data.n = value
}
})
return obj //这就是代理
}

上面的方法就是把原先的数据复制一遍,再删掉用新数据来填补,这样你就不能通过对象修改我的数据

这就是响应式,vue监听了这个数值,vue 会让 vm 成为 myData 的代理,vue 会对 myData 的所有属性进行监控,当数值发生改变的时候,vue就重新渲染

而原理是把一个普通的 JavaScript 对象传入 Vue 实例作为data选项,Vue 将遍历此对象所有的属性,并使用Object.defineProperty把这些属性全部转为getter/setter

总结

Vue会让vm成为myData的代理(proxy)

所以你对vm的操作就相当于对myData进行的操作,同时你还能通过this来访问到vm,因为this就是vm,vm就是myData的代理所以再vue中你可以通过this来读取data的值。

然后再通过上面说过的监听来对myData的所有属性进行监控

为什么要监控?

为了防止myData的属性变了,vm还不知道,那知道了又如何?知道了属性变了就能调用render(data)了呀让ui自动刷新了啊,这就是响应

Vue 的 Data 的 bug

image.png image.png