vue3.0 响应式系统

本文深入探讨Vue3.0的响应式系统,包括Proxy对象的使用,讲解reactive、ref、toRefs和computed的实现细节。通过示例展示如何创建和管理响应式对象,同时阐述了依赖收集和触发更新的过程。
摘要由CSDN通过智能技术生成

介绍

  • Proxy实现监听属性
  • 多层属性嵌套,在访问属性的过程中处理下一级属性
  • 默认监听动态添加的属性
  • 默认件套属性的删除操作
  • 默认监听数组索引和length属性
  • 可以作为单独模块使用

核心方法

  • reactive/ref/toRefs/computed
  • effect
  • track
  • trigger

Proxy对象

'use strict'
    问题1set 和 deleteProperty 中需要返回布尔类型的值
           在严格模式下,如果返回 false 的话会出现 Type Error 的异常
    const target = {
   
      foo: 'xxx',
      bar: 'yyy'
    }
    // Reflect.getPrototypeOf()
    // Object.getPrototypeOf()
    const proxy = new Proxy(target, {
   
      get (target, key, receiver) {
   
        // return target[key]
        return Reflect.get(target, key, receiver)
      },
      set (target, key, value, receiver) {
   
        // target[key] = value
        return Reflect.set(target, key, value, receiver)
      },
      deleteProperty (target, key) {
   
        // delete target[key]
        return Reflect.deleteProperty(target, key)
      }
    })

    proxy.foo = 'zzz'
    // delete proxy.foo
// 问题2:Proxy 和 Reflect 中使用的 receiver

    // Proxy 中 receiver:Proxy 或者继承 Proxy 的对象
    // Reflect 中 receiver:如果 target 对象中设置了 getter,getter 中的 this 指向 receiver

    const obj = {
   
      get foo() {
   
        console.log(this)
        return this.bar
      }
    }

    const proxy = new Proxy(obj, {
   
      get (target, key, receiver) {
   
        if (key === 'bar') {
    
          return 'value - bar' 
        }
        return Reflect.get(target, key, receiver)
      }
    })
    console.log(proxy.foo)

Proxy 对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)。

术语
handler
包含捕捉器(trap)的占位符对象,可译为处理器对象。
traps
提供属性访问的方法。这类似于操作系统中捕获器的概念。
target
被 Proxy 代理虚拟化的对象。它常被作为代理的存储后端。根据目标验证关于对象不可扩展性或不可配置属性的不变量(保持不变的语义)。
语法
const p = new Proxy(target, handler)
参数
target
要使用 Proxy 包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)。
handler
一个通常以函数作为属性的对象,各属性中的函数分别定义了在执行各种操作时代理 p 的行为。
方法
Proxy.revocable()
创建一个可撤销的Proxy对象。
handler 对象的方法
handler 对象是一个容纳一批特定属性的占位符对象。它包含有 Proxy 的各个捕获器(trap)。

所有的捕捉器是可选的。如果没有定义某个捕捉器,那么就会保留源对象的默认行为。

示例
基础示例
在以下简单的例子中,当对象中不存在属性名时,默认返回值为 37。下面的代码以此展示了 get handler 的使用场景。

const handler = {
   
    get: function(obj, prop) {
   
        return prop in obj ? obj[prop] : 37;
    }
};

const p = new Proxy({
   }, handler);
p.a = 1;
p.b = undefined;

console.log(p.a, p.b);      // 1, undefined
console.log('c' in p, p.c); // false, 37

无操作转发代理
在以下例子中,我们使用了一个原生 JavaScript 对象,代理会将所有应用到它的操作转发到这个对象上。

let target = {
   };
let p = new Proxy(target, {
   });

p.a = 37;   // 操作转发到目标

console.log(target.a);    // 37. 操作已经被正确地转发

验证
通过代理,你可以轻松地验证向一个对象的传值。下面的代码借此展示了 set handler 的作用。

let validator = {
   
  set: function(obj, prop, value) {
   
    if (prop === 'age') {
   
      if (!Number.isInteger(value)) {
   
        throw new TypeError('The age is not an integer');
      }
      if (value > 200) {
   
        throw new RangeError('The age seems invalid');
      }
    }

    // The default behavior to store the value
    obj[prop] = value;

    // 表示成功
    return true;
  }
};

let person = new Proxy({
   }, validator);

person.age = 100;

console.log(person.age);
// 100

person.age = 'young';
// 抛出异常: Uncaught TypeError: The age is not an integer

person.age = 300;
// 抛出异常: Uncaught RangeError: The age seems invalid

扩展构造函数
方法代理可以轻松地通过一个新构造函数来扩展一个已有的构造函数。这个例子使用了construct和apply。

function extend(sup, base) {
   
  var descriptor = Object.getOwnPropertyDescriptor(
    base.prototype, "constructor"
  );
  base.prototype = Object.create(sup.prototype);
  var handler = {
   
    construct: function(target, args) {
   
      var obj 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值