• vue3响应式原理:Proxy + Reflect


    vue3响应式原理:Proxy + Reflect,代码示例

     // 目标对象
       const user = {
           name: '小小',
           age: 20,
           wife: {
               name: '小明',
               age: 19
           }
       }
    
       // 把目标对象变成代理对象
       const proxyUser = new Proxy(user, {
           // 获取
           get(target, prop) {
               console.log('get方法调用了')
               console.log(target)
               return Reflect.get(target, prop)
    
           },
           // 新增、修改
           set(target, prop, val) { 
               console.log('set方法调用了')
               return Reflect.set(target, prop, val)
    
           },
           // 删除
           deleteProperty(target, prop) {
               console.log('delete方法调用了')
               return Reflect.deleteProperty(target, prop)
    
           }
       })
    
       // 触发get
       console.log(proxyUser.name)
       // 触发set
       proxyUser.age += 1;
       proxyUser.gender = 'man'
       // 触发delete
       delete proxyUser.name
       // 更新目标对象中的某个属性对象中的属性值
       proxyUser.wife.name = "天天天三百"
       console.log(user)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    Reflect学习

    1、Reflect是什么

    Reflect 是一个window 内置的一个全局对象,它提供拦截 JavaScript 操作的方法

    与大多数全局对象不同,Reflect并非一个构造函数,所以不能通过new 运算符对其进行调用,或者将Reflect对象作为一个函数来调用。Reflect的所有属性和方法都是静态的(就像Math对象)

    2、Reflect常用的静态方法
    2.1、Reflect.get(target, propertyKey[, receiver]) ---- 从一个对象中取属性值
    • target: 需要取值的目标对象
    • propertyKey: 需要获取的值的键值
    • receiver:receiver则为getter调用时的this值。

    返回值:属性的值

    // Object
    var obj = { x: 1, y: 2 };
    Reflect.get(obj, "x"); // 1
    
    // Array
    Reflect.get(["zero", "one"], 1); // "one"
    
    // Proxy with a get handler
    var x = {p: 1};
    var obj = new Proxy(x, {
      get(t, k, r) { return k + "bar"; }
    });
    Reflect.get(obj, "foo");   // "foobar"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    2.2、Reflect.set(target, propertyKey, value[, receiver]) ---- 为对象设置或修改属性值
    • target : 设置属性的目标对象。
    • propertyKey : 设置的属性的名称。
    • value : 设置的值。
    • receiver : receiver则为setter调用时的this值。

    返回值 : 返回一个 Boolean 值,表明是否成功设置属性。

    // Object
    var obj = {};
    Reflect.set(obj, "prop", "value"); // true
    obj.prop; // "value"
    
    // Array
    var arr = ["duck", "duck", "duck"];
    Reflect.set(arr, 2, "goose"); // true
    arr[2]; // "goose"
    
    Reflect.set(arr, "length", 1); // true
    arr; // ["duck"];
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    2.3、Reflect.deleteProperty(target, propertyKey) ---- 用于删除属性
    • target : 删除属性的目标对象。
    • propertyKey : 需要删除的属性的名称

    返回值 : 返回一个 Boolean 值,表明该属性是否被成功删除.

    var obj = { x: 1, y: 2 };
    Reflect.deleteProperty(obj, "x"); // true
    obj; // { y: 2 }
    
    var arr = [1, 2, 3, 4, 5];
    Reflect.deleteProperty(arr, "3"); // true
    arr; // [1, 2, 3, , 5]
    arr[3]  // undefined 
    
    // 如果属性不存在,返回 true
    Reflect.deleteProperty({}, "foo"); // true
    
    // 如果属性不可配置,返回 false
    Reflect.deleteProperty(Object.freeze({foo: 1}), "foo"); // false
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    2.4、Reflect.has(target, propertyKey) ----- 需要检查目标对象是否存在此属性。
    • target : 目标对象。
    • propertyKey : 属性名

    返回值 : 返回一个 Boolean 值,表示是否存在此属性

    Reflect.has({x: 0}, "x"); // true
    Reflect.has({x: 0}, "y"); // false
    
    // 如果该属性存在于原型链中,返回 true
    Reflect.has({x: 0}, "toString");
    
    • 1
    • 2
    • 3
    • 4
    • 5
    2.5、Reflect.apply(target,thisArgument,argumentsList)
    • target: 目标函数。
    • thisArgument: target 函数调用时绑定的 this 对象。
    • argumentsList: target 函数调用时传入的实参列表,该参数应该是一个类数组的对象。
    Reflect.apply(Math.floor, undefined, [1.75]);    // 1
    Reflect.apply("".charAt, "ponies", [3]);   // "i"
    
    • 1
    • 2
    2.6、其它方法,参考地址:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Reflect/deleteProperty

    注意:Reflect 不支持 ie浏览器,所以Vue3不支持ie
    在这里插入图片描述

    Vue3中的 Proxy + Reflect 解决了 Vue2 Object.defineProperty中遇到的哪些问题

    在使用Object.defineProperty的时候,我们遇到的问题有:

    1.一次只能对一个属性进行监听,需要遍历来对所有属性监听。这个我们在上面已经解决了。
    2. 在遇到一个对象的属性还是一个对象的情况下,需要递归监听。
    3. 对于对象的新增属性,需要手动监听
    4. 对于数组通过push、unshift方法增加的元素,也无法监听

    这些问题在Proxy中都轻松得到了解决。

    Vue3的响应式,为什么 Proxy 要配合 Reflect 一起使用,不能直接使用target[key]返回

    ①保证上下文环境中的 this, 指向的是代理后的proxy对象

    举个例子

    const target = {
        foo: 24,
        get bar () {
            return this.foo
        }
    }
    
    const observed = reactive(target)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    此时,如果不用 Reflect.get,而是 target[key],那么这里上下文中的 this 就指向target,而不是 observed

    那么,之后你通过this去访问数据时,你访问的就是代理之前的对象,而不是代理之后的Proxy对象。这样用户对对象的操作你就无法监听到了,就无法触发回调,进行其它操作了;

    而Reflect的get、set方法中的第三个参数receiver,就是修改this指向的;所以,我们要通过 Reflect 中的get、set方法将上下文中的 this 指向代理对象。这样的话,之后访问数据时,访问的就是Proxy代理后的对象了,同时也就会触发Proxy对象中的get、set方法了,从而也就能触发回调,进行其它操作了;

  • 相关阅读:
    C++入门之命名空间详解
    线性代数的本质(八)——内积空间
    WebKit与CSSOM视图模块:探索现代Web布局的协同进化
    JVM系列 运行时数据区
    linux下日志查看命令
    Flutter 像素编辑器#04 | 导入导出图像
    ALEXNET论文及其复现代码
    CVD和PECVD管式炉真空控制系统的升级改造
    常见的Elasticsearch操作
    【Pytorch报错】RuntimeError: cuDNN error: CUDNN_STATUS_INTERNAL_ERROR
  • 原文地址:https://blog.csdn.net/yiyueqinghui/article/details/126391362