# 什么是响应式

响应式就是在依赖数据的地方,当数据发生改变的时候,依赖数据的地方执行相应的方式进行响应。

# 如何成为响应式

使用proxy结合Reflect 什么是proxy和Reflect

let obj ={
  age:1,
  name:'a'
}
//receiver就是proxyObj
let proxyObj = new Proxy(obj,{
  get:function(target,key,receiver){
    console.log('---')
    return Reflect.get(target,key,receiver)
  },
  set:function(target,key,val,receiver){
    Reflect.set(target,key,val,receiver)
  }
})
//测试
console.log(proxyObj.name)
// 'a' 
// '---'

# 依赖收集的类

class Depend{
  constructor(){
    this.arr=[]
  }
  addDepend(sub) {
    this.arr.push(sub)
  }
  notify(){
    this.arr.forEach(item=>item())
  }
}

# 依赖收集的管理

let weakMap = new WeakMap()
function getDepend(target,key){
  let map = weakMap.get(target)
  if(!map) {
    map = new Map()
    weakMap.set(target,map )
  }
  let dep = map.get(key)
  if(!dep) {
    dep = new Depend()
    map.set(key,dep)
  }
  return dep;
}

vue3依赖收集的数据结构

# 完整demo

//1.收集依赖的depend类
class Depend{
  constructor(){
    this.arr=[]
  }
  addDepend(sub) {
    this.arr.push(sub)
  }
  notify(){
    this.arr.forEach(item=>item())
  }
}
//2.全局变量,为了获取watchfn中正传入的fn,便于在get中获取。
let activeReactiveFn = null;
//3.vue3 依赖收集的数据结构,如上图所示。
let weakMap = new WeakMap()
//4.普通对象
let obj ={
  age:1,
  name:'a'
}
//5.代理对象,get set劫持。
let proxyObj = new Proxy(obj,{
  get:function(target,key,receiver){
    //
    let dep = getDepend(target,key)
    dep.addDepend(activeReactiveFn)
    return Reflect.get(target,key,receiver)
  },
  set:function(target,key,val,receiver){
    let dep = getDepend(target,key)
    dep.notify()
    Reflect.set(target,key,val,receiver)
  }
})
//6.获取对象属性对应的depend。没有就创建。
function getDepend(target,key){
  let map = weakMap.get(target)
  if(!map) {
    map = new Map()
    weakMap.set(target,map )
  }
  let dep = map.get(key)
  if(!dep) {
    dep = new Depend()
    map.set(key,dep)
  }
  return dep;
}
//7.函数首次执行会触发get.收集此时的fn在对应的depend中。
function watchFn(fn) {
  activeReactiveFn = fn
  fn()
  activeReactiveFn = null
}
//8.正式测试
watchFn(function(){
  console.log('1.用到了 obj的name会被收集',proxyObj.name);
})
watchFn(function(){
  console.log('2.用到了 obj的name会被收集',proxyObj.name);
})
console.log('--------------set触发,回调重新执行-----------------');
proxyObj.name='我改了,回调要执行了'