1.不要认为数据发生改变,界面跟着更新就代表是Vue的响应式的体现。数据发生改变并不是理所当然的。

2.要想理解Vue响应式原理就要解决以下两个问题

  1. 问题1. 通过app.message = “呵呵呵” 修改数据,Vue内部是如何监听message的数据发生了改变
    解决1:使用了Object.defineProperty监听对像属性的变化
  2. 问题2. 当数据发生了改变,vue是如何通知界面上的name,age,message进行数据更新,从而刷新界面。
    解决2:发布订阅者模式

3.Object.defineProperty的原理

3.1. 当vue在data()中创建一个匿名对像后,vue内部就会默认将这个匿名对像赋值给Vue内部的一个obj对象
const app = new Vue({
  el: '#app',
  data() {
    return {
      name: 'ckk',
      age: 18,
      message: "哈哈哈"
    }
  }
})
3.2. vue内部会创建一个obj对像接收data()中的匿名对像。
const obj = {
  name: 'ckk',
  age: 18,
  message: "哈哈哈"
}
3.3. 遍历obj对象,通过defineProperty对obj进行重定义,
Object.keys(obj).forEach(key => {
  //1.将每个值都保存在value变量中
  let value = obj[key]
  //2. 对obj进行重定义
  Object.defineProperty(obj, key, {
    //2.1 set方法可以监听key的改变
    set(newValue){
      console.log('监听' + key +'的改变')
      value = newValue
    },
    //2.2 get方法可以获取key对应的值
    get(){
      console.log('获取' + key +'的对应值')
      return value
    }
  })
})
3.4. 结果测试
1.在chrome代码调试器里输入obj.message = '呵呵呵',触发set方法
        obj.message = '呵呵呵' 
2.在chrome代码调试器里输入obj.message,触发set方法 
        obj.message 

4.发布订阅者模式

4.1 发布者
  1. 介绍:通知界面上的name,age,message进行数据更新,从而刷新界面
  2. 创建发布者
    //Dep=>dependency(依赖)
    class Dep {
      constructor(){
        //subs=>subscribes
        this.subs = []
      }
      //这个函数是为了增加匿名对像中的属性(name,age,message),并通知他们进行update
      addSub(watcher){
        this.subs.push(watcher)
        console.log(this.subs)
      }
      //发布update的通知
      notify(){
        this.subs.forEach(item => {
          item.update()
        })
      }
    }
4.2 订阅者
  1. 介绍:可以理解为匿名对像中的属性(例如name,age,message)
  2. 创建订阅者
    //订阅者
    class Watcher {
      constructor(name){
        this.name = name
      }
      //订阅者进行数据更新
      update(){
        console.log(this.name + '发生了update')
      }
    }

5.全部流程

5.1 简介

本代码默认在Vue创建data()后,默认已经将data()中匿名函数对像已经传递给Vue内部的obj对像,
我这里解释的也是传递给obj后的响应式原理处理的过程

5.2 过程
  1. 在外部创建一个发布者(dept)
  2. 在get方法中创建一个订阅者(watcher)
  3. 在get方法中将订阅者加入发布者的监听数组中(subs)
  4. 更改数据,使发布者通知订阅者触发update方法
5.3 code
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <script>
    /*当vue创建data()这个对像后,vue内部就会默认将这个data()对象赋值给一个Vue内部的一个obj对象*/
  /*1. Object.defineProperty 监听对像属性的变化 */
    const obj = {
      name:'ckk',
      age:18,
      message:'我爱中国'
    }
    Object.keys(obj).forEach(key => {
      let value = obj[key]
      Object.defineProperty(obj, key, {
        set(newValue){
          console.log('----------------set----------------------')
          //console.log('监听' + key +'的改变')
          //告诉谁了?谁在用了?
          //根据解析html代码,获取到哪些人在用key
          value = newValue
          dept.notify() 
        },
        get(){
          console.log('----------------get----------------------')
          //console.log('获取' + key +'的对应值')
          //张三:get,进行update
          //李四:get,进行update
          //王五:get,进行update
          let w1 = new Watcher(key)
          dept.addSub(w1)
          return value
        }
      })
    })

    //2.发布订阅者模式:通知界面上的name,age,message进行数据更新,从而刷新界面
    //Dep=>dependency(依赖)
    //发布者
    class Dep {
      constructor(){
        //subs=>subscribes
        this.subs = []
      }
      //这个函数是为了增加匿名对像中的属性(name,age,message),并通知他们进行update
      addSub(watcher){
        this.subs.push(watcher)
        console.log(this.subs)
      }
      //发布update的通知
      notify(){
        this.subs.forEach(item => {
          item.update()
        })
      }
    }
    //创建一个匿名对像中的属性类(name,age,message)
    //订阅者
    class Watcher {
      constructor(name){
        this.name = name
      }
      //订阅者进行数据更新
      update(){
        console.log(this.name + '发生了update')
      }
    }
    // 新建一个发布者
    const dept = new Dep()
  </script>
</body>
</html>
5.4 测试

评 论