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)

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"
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"];
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
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");
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"
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)

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

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

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

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值