vue2 与 vue3 的响应式实现 
在我印象中, vue2 使用的是defineProperty, vue3 使用的是一个proxy. 翻了文档才发现我错了.
vue2 
众所周知, vue2 基本上都是选项式 API, 需要的响应式数据都写在 data 函数里, 这个函数返回一个对象. 因此只需要让这个对象具有响应式就可以了. 同时需要注意让data里的对象和数组都要有响应式.
function makeReactive(obj) {
  if (typeof obj !== 'object' || obj === null) {
    // 不是对象就抛错
    throw new Error('need an object')
  }
  Object.keys(obj).forEach((key) => {
    let originValue = obj[key]
    if (typeof originValue === 'object' && originValue !== null) {
      obj[key] = makeReactive(originValue)
    }
    Object.defineProperty(obj, key, {
      get() {
        console.log(`Getting ${key}: ${originValue}`)
        return originValue
      },
      set(newValue) {
        console.log(`Setting ${key} to ${newValue}`)
        console.log(typeof newValue === 'object' && newValue !== null)
        if (typeof newValue === 'object' && newValue !== null) {
          obj[key] = makeReactive(newValue)
        }
        else {
          originValue = newValue
        }
      },
    })
  })
}这样其实会有一些问题. 很难追踪到data里某个对象增加了一个key-value, 也很难追踪某个数组的push, pop等. 这是因为在响应式化的时候是通过遍历所有属性赋予响应式导致的, 之前没出现过的属性当然就跟踪不了.
同时也会产生一个效率问题, 那就是大数组的时候. 假如有100w的数组, 那么我就需要遍历100w次, 这太恐怖了. 对此有一个解决方案, 使用冻结对象, 这样vue2就不会尝试响应式化了. 或者明明以_开头.
vue3 
众所周知, vue3提供了ref和reactive两种. 它们还是有点区别的.
reactive用于对象(当然也包括数组), 它使用的是proxy.
function reactive(obj) {
  if (typeof obj !== 'object' || obj === null) {
    throw new Error('need an object')
  }
  return new Proxy(obj, {
    get(target, key) {
      // 收集依赖
      return target[key]
    },
    set(target, key, value) {
      // 触发事件
      target[key] = value
      return true
    }
  })
}这里只是简单实现, 实际可能更复杂. 简单对比一下就可以发现:
- 不需要遍历, 性能更好 
- 即使之前没有出现过的属性也有响应式 
这里其实还有一点优化, 就是访问子对象时才会创建一个proxy而不是立刻递归地创建.
ref主要用在普通的值, 比如数字, 字符串等. 像这种主要对值访问而不是某一个key-value访问的属性用proxy就不太方便了.
class RefImf {
  _value
  constructor(value) {
    this._value = value
  }
  get value() {
    // 收集依赖
    return value
  }
  set value(value) {
    // 触发事件
    this._value = value
  }
}
function ref(value) {
  return new RefImf(value)
}简单使用getter/setter拦截器就可以实现值的响应式了.
平时我们给ref传一个object时, 用的就不是这个getter/setter了, 而是使用proxy, vue3会帮我们处理好.
ref和reactive的区别 
区别在于使用ref的话之后需要.value才能获取值, 使用reactive可以不需要.value.
同时ref允许传递任意值, reactive只允许传递对象.
后言 
怎么说呢, 有点想自己写一遍vue, 我感觉我很难再有所突破了, 如果每天只是写写小页面. 使用echarts, canvas, three.js也会给我带来提升, 不过怎么说呢, 我个人不太喜欢这些东西, 我也没有设计审美, 不知道用这些东西做什么.
我大概会开一个仓库复现vue的一些东西吧, 不知道能坚持到什么时候.