7. vue3.0 中为什么要使用 Proxy,它相比以前的实现方式有什么改进

  • Post author:
  • Post category:vue




7. vue3.0 中为什么要使用 Proxy,它相比以前的实现方式有什么改进



7.1 原回答

  1. Vue2.x通过给每个对象添加

    getter setter

    属性去改变对象,实现对数据的观测,Vue3.x通过Proxy代理目标对象,且一开始只代理最外层对象,嵌套对象

    lazy by default

    ,性能会更好
  2. 支持数组索引修改,对象属性的增加,删除



7.2 查阅补充



(1)Proxy


  • Proxy 是一个对象,它包装了另一个对象,并允许你拦截对该对象的任何交互。

    • Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。Proxy 这个词的原意是代理,用在这里表示由它来“代理”某些操作,可以译为“代理器”。
  • 我们这样使用它:

    const proxy = new Proxy(target, handler)

    • target 是 目标对象
    • proxy 是 代理对象
  • 使用 Proxy 的一个难点是

    this

    绑定。

    • 虽然 Proxy 可以代理针对目标对象的访问,但它不是目标对象的透明代理,即不做任何拦截的情况下,也无法保证与目标对象的行为一致。主要原因就是在 Proxy 代理的情况下,目标对象内部的

      this

      关键字会指向 Proxy 代理。

      const target = {
        m: function () {
          console.log(this === proxy);
        }
      };
      const handler = {};
      
      const proxy = new Proxy(target, handler);
      
      target.m() // false
      proxy.m()  // true
      
      

      上面代码中,一旦

      proxy

      代理

      target



      target.m()

      内部的

      this

      就是指向

      proxy

      ,而不是

      target

    • 我们希望任何方法都绑定到这个 Proxy,而不是目标对象,这样我们也可以拦截它们。值得庆幸的是,ES6 引入了另一个名为

      Reflect

      的新特性,它允许我们以最小的代价消除了这个问题:

      const dinner = {
        meal: 'tacos'
      }
      
      const handler = {
        get(target, property, receiver) {
          return Reflect.get(...arguments)
        }
      }
      
      const proxy = new Proxy(dinner, handler)
      console.log(proxy.meal)
      
      // tacos
      
  • Vue 响应性的步骤

    • 当一个值被读取时进行追踪:proxy 的 get 处理函数中 track 函数记录了该 property 和当前副作用。

    • 当某个值改变时进行检测:在 proxy 上调用 set 处理函数。

    • 重新运行代码来读取原始值:trigger 函数查找哪些副作用依赖于该 property 并执行它们。

      const dinner = {
        meal: 'tacos'
      }
      
      const handler = {
        get(target, property, receiver) {
          track(target, property)//1.一个名为 track 的处理器函数中跟踪一个 property 何时被读取.它将检查当前运行的是哪个副作用,并将其与 target 和 property 记录在一起。这就是 Vue 如何知道这个 property 是该副作用的依赖项。
          return Reflect.get(...arguments)
        },
          //2.在 property 值更改时重新运行这个副作用。为此,我们需要在代理上使用一个 set 处理函数
        set(target, property, value, receiver) {
          trigger(target, property)//3.重新运行代码来读取原始值:trigger 函数查找哪些副作用依赖于该 property 并执行它们。
          return Reflect.set(...arguments)
        }
      }
      
      const proxy = new Proxy(dinner, handler)
      console.log(proxy.meal)
      
      // tacos
      



版权声明:本文为qq_43456781原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。