这里的代码只是说明最好用this

  1. const myData = {
  2. n:0
  3. }
  4. const vm = new Vue({
  5. data(){
  6. return {
  7. n:0
  8. }
  9. },
  10. template:`
  11. <div>{{n}}<button @click="add">+10</button></div>
  12. `,
  13. methods:{
  14. add(){
  15. this.n += 10 //最好用this.n,因为一般data数据都写在opitons中了
  16. //myData.n += 10
  17. }
  18. }
  19. }).$mount("#app")
  20. setTimeout(()=>{
  21. myData.n +=10
  22. console.log(myData) //本节课精髓
  23. })

什么是数据响应式

如果修改Vue的实例vm.n的值,UI就会自动响应。

先插入一些知识点

先讲一下ES6的新语法,getter和setter

getter

  1. let obj2 = {
  2. 姓:"高",
  3. 名:"圆圆",
  4. //get表示后面只是一个属性,只是以函数形式来定义而已,是计算属性
  5. get 姓名(){
  6. return this.姓 + this.名;
  7. },
  8. age:18
  9. }
  10. //调用不需要加括号
  11. obj2.姓名

setter

  1. let obj3 = {
  2. 姓:"高",
  3. 名:"圆圆",
  4. set 姓名(xxx){
  5. this.姓 = xxx[0]
  6. this.名 = xxx.slice(1)
  7. },
  8. age = 18
  9. }
  10. //给姓名设置值
  11. obj3.姓名 = "刘诗诗"

虽然可以对”姓名”进行读和写,但并不存在一个真正的姓名属性,只存在”get 姓名”和”set 姓名”
image.png

再学习一下Object.defineProperty

给obj3添加一个属性

  1. var _xxx = 0 //这个声明,是用来放xxx的值的
  2. //注意,这里的xxx是不存在的属性
  3. Object.defineProperty(obj3,"xxx",{
  4. get(){
  5. return _xxx
  6. },
  7. set(value){
  8. _xxx = value
  9. }
  10. })

几个实验

需求一,用Object.defineProperty定义

  1. let data0 = {
  2. n:0
  3. }
  4. //需求一,用Object.defineProperty定义
  5. let data1 = {}
  6. Object.defineProperty(data1,"n",{
  7. value: 0
  8. })
  9. console.log(`需求一:${data1.n}`)
  10. //总结:这傻逼语法把事情搞复杂了?非也,继续看

需求二,不能小于0,即data2.n = -1应该无效,但data2.n = 1有效

  1. let data2 = {}
  2. data2._n = 0 //_n 用来偷偷存储n的值
  3. Object.defineProperty(data2,'n',{
  4. get(){
  5. return this._n
  6. },
  7. set(value){
  8. if(value < 0) return
  9. this._n = value
  10. }
  11. })
  12. console.log(`需求二:${data2.n}`)

需求三,使用代理

  1. let data3 = proxy({data:{n:0}}) //括号里是匿名对象,无法访问
  2. function proxy({data}){ //解构赋值
  3. const obj = {}
  4. //这里的n,写死了,理论上应该遍历data的所有key,这里做了简化
  5. //因为我怕你们看不懂
  6. Object.defineProperty(obj,'n',{
  7. get(){
  8. return data.n
  9. },
  10. set(value){
  11. if(value < 0) return
  12. data.n = value
  13. }
  14. })
  15. return obj
  16. }
  17. console.log(`需求三:${data3.n}`)
  18. data3.n = -1
  19. console.log(`需求三:${data3.n},设置为-1失败`)
  20. data3.n = 1
  21. console.log(`需求三:${data3.n},设置为1成功`)

需求四,绕过代理仍然能改

  1. let myData = {n:0}
  2. let data4 = proxy({data:myData})
  3. console.log(`杠精:${data4.n}`)
  4. myData.n = -1
  5. console.log(`杠精:${data4.n},设置为-1失效了吗?`)
  6. //现在还不是可以改myData

需求五,就算用户擅自修改myData,也要拦截他

  1. let myData5 = {n:0}
  2. let data5 = proxy2({data.myData5})
  3. function proxy2(data){
  4. let value = data.n //保存最开始的n
  5. Object.defineProperty(data,'n',{ //这里声明的n是虚拟属性,放到了data上,会覆盖初始的n
  6. get(){
  7. return value
  8. },
  9. set(newValue){
  10. if(newValue<0) return
  11. value = newValue
  12. }
  13. })
  14. //就加了上面几句,这几句话会监听data,是监听的逻辑
  15. const obj = {}
  16. Object.defineProperty(obj,'n',{
  17. get(){
  18. return data.n
  19. },
  20. set(value){
  21. if(value < 0) return
  22. data.n = value
  23. }
  24. })
  25. //这几句是代理的逻辑
  26. return obj //obj就是代理
  27. }
  28. console.log(`需求五:${data5.n}`)
  29. myData5.n = -1
  30. console.log(`需求五:${data5.n},设置为-1失效了`)
  31. myData5.n = 1
  32. console.log(`需求五:${data5.n},设置为1成功了`)

以上是任何时候都能监听数据的修改,原理等同于vue的内部源码。

小结:

Object.defineProperty

可以给对象添加属性value
可以给对象添加getter/setter
getter/setter用于对属性的读写进行监控

啥是代理(设计模式)

对myData对象的属性读写,全权由另一个对象vm负责
那么vm就是myData的代理(类似房东租房)
比如myData.n不用,偏要用vm.n来操作myData.n

vm=new Vue({data:myData})

一、会让vm成为myData的代理(proxy)
二、会对myData的所有属性进行监控
为什么要监控,为了放置myData的属性变了,vm不知道
vm知道了又如何?知道了属性变了就可以调用render(data)呀!
UI=render(data)

资料来源:饥人谷