Vue3 为什么用Proxy重构

Date:

Vue3 为什么用Proxy重构


目录

1. Proxy

1.1 Proxy 的颠覆性

Object.defineProperty 是对象的属性劫持,只能劫持对象的属性。 Proxy 是对象的代理,可以代理对象的属性、方法、甚至整个对象,这不是一个level的。

Proxy的handle里提供了一堆拦截方法(trap),可以拦截对象的所有操作。 | 方法 | 描述 | | — | — | | get | 拦截对象的属性读取 | | set | 拦截对象的属性设置 | | has | 拦截对象的in操作符 | | deleteProperty | 拦截对象的delete操作符 | | apply | 拦截对象的函数调用 | | construct | 拦截对象的new操作符 |

Proxy可以做校验器、可以做私有属性…

1.2 vue3 为什么用proxy重构

Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象 如果对象新增了属性?如果我是一个10000长度的数组?

vue2 的响应式依赖于Object.defineProperty

  Object.defineProperty(obj, key, {
    enumerable: true,
    configurable: true,
    get: function reactiveGetter () {
      // ...

      // 收集依赖
      dep.depend()
   
      return value
    },
    set: function reactiveSetter (newVal) {
      // ...

      // 通知视图更新
      dep.notify()
    }
  })

在组件初始化时的initState中,其中会遍历data中的所有属性,并调用Object.defineProperty来劫持这些属性。

当在运行时新增属性的话,observer 无法监听到。

对于对象,在vue2中,通过$set来新增属性。

this.$set(target, propertyName/index, value)

对于数组,当然你可以遍历数组,给每个元素都设置响应式,但这样性能太差了,vue2也没这么做。

vue2采用的解决方案是:hack数组的7个方法, 调用基本方法之后,新增监听以及通知更新 push | pop | shift | unshift | splice | sort | reverse

  const methodsToPatch = [
    'push',
    'pop',
    'shift',
    'unshift',
    'splice',
    'sort',
    'reverse'
  ]

  methodsToPatch.forEach(function (method) {
    const original = arrayProto[method]
    // def <==> Object.defineProperty
    def(arrayMethods, method, function mutator (...args) {
      const result = original.apply(this, args) // 调用原生方法

      const ob = this.__ob__  // ob就是observe实例observe才能响应式
      let inserted
      switch (method) {
        // push和unshift方法会增加数组的索引,但是新增的索引位需要手动observe的
        case 'push':
        case 'unshift':
          inserted = args
          break
        // 同理,splice的第三个参数,为新增的值,也需要手动observe
        case 'splice':
          inserted = args.slice(2)
          break
      }
      // 其余的方法都是在原有的索引上更新,初始化的时候已经observe过了
      if (inserted) ob.observeArray(inserted)
      // dep通知所有的订阅者触发回调
      ob.dep.notify()
      return result
    })
  })

TS是在 JavaScript 上增加一套静态类型系统(编译时(开发时)进行类型分析)

在JS的基本类型和引用类型上,增加了一套类型系统

  • JS的基本类型+引用类型 number | string | boolean | null | undefined | object | symbol
  • enum 类型 enum LogLevel { info = 'info', warn = 'warn', error = 'error' }
  • tuple 类型 [string, number]
  • any 类型 any
  • unknown 类型 unknown
  • never 类型 never
  • void 类型 void

  • interface 类型 interface Person { name: string, age: number }
  • 箭头函数 (a: string) => string
  • 函数 function(a: string): string
  • 泛型 T extends object

  • 交叉类型 A & B 对象属性多合一
  • 联合类型 A | B 类型多合一
  • 类型断言 a as string

参考资料

(vue3-one-piece)[https://vue3js.cn/]