一说一下对响应式数据的理解?

1.1 如何实现响应式数据

数组和对象类型当值变化时如何劫持到,对象内部通过 definereactive 方法,使用 Object.defineProperty 将属性进行劫持(只会劫持已经存在的属性),手术则是通过重写数组的方法来实现,多层对象是通过递归来实现劫持,Vue3 则采用的是 proxy

1.2 vue 2 的缺陷

  • 在 vue 2 的时候使用 defineProperty 来进行数据劫持,需要对属性进行重写添加 gettersetter 所以性能很差
  • 当新增属性和删除属性时无法监听变化,需要通过 $set$delete 实现
  • 数组不采用 defineProperty 来进行劫持(浪费性能,对所有索引进行劫持会造成性能浪费)需要对数组单独进行处理
  • 对于 es6 中新产生的 Map 和 Set 这些数据结构不支持

1.3 vue 2 和 vue 3 实现对比

vue 2:

<!DOCTYPE html>
<html lang="en">
  <body>
    <script>
      let obj = {
        name: 'aa',
        age: 14,
        n: {
          num: 1,
        },
      }

      function definereactive(target, key, value) {
        observer(value)
        Object.defineProperty(target, key, {
          get() {
          // 记录对应的渲染watcher
            return value
          },
          set(newValue) {
          // 让记录的watcher重新执行一下
            if (value !== newValue) {
              value = newValue
              observer(newValue)
            }
          },
        })
      }

      function observer(data) {
        if (typeof data !== 'object' || typeof data === null) {
          return data
        }
        for (let key in data) {
          definereactive(data, key, data[key])
        }
      }
      observer(obj)
    </script>
  </body>
</html>```

vue 3:

```js
let obj = {
  name: 'aa',
  age: 12,
  n: {
    num: 2,
  },
}
let handler = {
  get(target, key) {
    // 收集effect
    let temp = target[key]
    if (typeof temp === 'object') {
      return new Proxy(temp, handler)
    }

    return temp
  },
  set(target, key, value) {
    // 触发effect的更新
    target[key] = value
  },
}

function reactive(target) {
  return new Proxy(target, handler)
}
const proxy = reactive(obj)
proxy.name = 100