当前位置: 首页 > article >正文

proxy代理机制和工作原理,reactive是怎么通过proxy实现响应式的

1. 什么是 Proxy

Proxy 是 JavaScript 中一个用于创建代理对象的构造函数,允许你定义基本操作(如属性查找、赋值、枚举、函数调用等)的自定义行为。通过 Proxy,你可以对一个对象进行拦截,并在该对象的操作上添加自定义逻辑。在 Vue 3 中,Proxy 被广泛用于实现响应式系统。

2. 代理机制

代理机制的核心在于以下几个方面:

目标对象:这是 Proxy 要代理的实际对象(即目标)。
处理器对象:这是一个对象,定义了拦截器函数,用于拦截对目标对象的操作。
当对 Proxy 代理的对象进行操作时,实际的操作会被发送到处理器对象中定义的拦截器函数,这些函数会处理相应的操作。

基本语法

const proxy = new Proxy(target, handler);
//target:要代理的对象。
//handler:定义拦截行为的处理器对象。

3.工作原理

Proxy 的工作原理主要依赖于内部方法和拦截机制。以下是一些重要的方面:

内部方法

Proxy 通过内部方法(如 [[Get]]、[[Set]] 等)来控制对象的行为。当你尝试对代理对象进行操作时,这些操作会被转换为对应的内部方法调用。

以下是一些常见的内部方法及其对应的拦截器函数:

[[Get]]:当获取对象的属性时调用,映射到 get 拦截器。
[[Set]]:当设置对象的属性时调用,映射到 set 拦截器。
[[Delete]]:当删除对象的属性时调用,映射到 deleteProperty 拦截器。
[[Has]]:当使用 in 操作符检查属性是否存在时调用,映射到 has 拦截器。
[[Apply]]:当函数被调用时调用,映射到 apply 拦截器。
[[Construct]]:当使用 new 操作符创建对象时调用,映射到 construct 拦截器。

3.1 拦截行为

通过实现处理器对象中的拦截器函数,你可以控制对目标对象的所有操作。例如:

const target = {
    name: 'John',
    age: 30
};

const handler = {
    get(target, prop, receiver) {
        console.log(`Getting ${prop}`);
        return Reflect.get(target, prop, receiver);
    },
    set(target, prop, value, receiver) {
        console.log(`Setting ${prop} to ${value}`);
        return Reflect.set(target, prop, value, receiver);
    }
};

const proxy = new Proxy(target, handler);

console.log(proxy.name); // Getting name -> "John"
proxy.age = 31;          // Setting age to 31
console.log(proxy.age);  // Getting age -> 31

proxy对于响应式对象的基本实现:reactive

reactive 对 Proxy 进行封装。它是 Vue 3 中实现响应式数据的一种方式,简化了用户的使用体验

reactive 函数用于将普通对象转换为响应式对象。通过 Proxy,reactive 可以拦截对对象的读取和写入操作,以实现依赖收集和自动更新的功能。

reactive 的实现原理

reactive 的内部实现主要依赖于 Proxy,它将目标对象包装成一个代理对象,并在 get 和 set 拦截器中定义逻辑。具体实现通常包含以下几个步骤:

创建代理对象:通过 new Proxy 创建一个代理对象,接收目标对象和处理器(handler)作为参数。
实现拦截器:
get 拦截器:用于拦截对对象属性的读取,可以在这里进行依赖收集。
set 拦截器:用于拦截对对象属性的写入,可以在这里进行更新通知。
简化版 reactive 实现示例,展示了如何使用 Proxy 创建响应式对象

function reactive(target) {
    // 存储依赖的简单实现
    const dependencies = new Map();

    // 创建代理
    return new Proxy(target, {
        get(target, prop, receiver) {
            // 收集依赖
            if (!dependencies.has(prop)) {
                dependencies.set(prop, new Set());
            }
            const deps = dependencies.get(prop);
            // 假设有一个全局的 effect 函数,用于注册依赖
            if (currentEffect) {
                deps.add(currentEffect);
            }
            return Reflect.get(target, prop, receiver);
        },
        set(target, prop, value, receiver) {
            // 更新目标对象
            const oldValue = target[prop];
            if (oldValue !== value) {
                Reflect.set(target, prop, value, receiver);
                // 通知依赖
                const deps = dependencies.get(prop);
                if (deps) {
                    deps.forEach(effect => effect());
                }
            }
            return true;
        }
    });
}

// 用于注册当前的 effect
let currentEffect = null;
function effect(fn) {
    currentEffect = fn;
    fn(); // 立即执行一次,以收集依赖
    currentEffect = null; // 执行完成后清空
}

// 使用 reactive
const state = reactive({ count: 0 });

effect(() => {
    console.log(`Count is: ${state.count}`);
});

// 修改 state.count 会自动触发 effect
state.count++; // Count is: 1
state.count++; // Count is: 2

当然实际上不会这么使用,而是采用下面的方式

例子:

import { reactive, effect } from 'vue';

// 创建响应式状态
const state = reactive({
    count: 0,
    message: 'Hello Vue!'
});

// 创建响应式副作用
effect(() => {
    console.log(`Count is: ${state.count}`);
    console.log(`Message is: ${state.message}`);
});

// 修改数据,触发更新
state.count++; // Count is: 1
state.message = 'Hello World!'; // Message is: Hello World!
state.count++; // Count is: 2

http://www.kler.cn/a/355396.html

相关文章:

  • [Unity]Unity集成NuGet-连接mysql时的发现
  • linux中docker命令大全
  • SRE 与 DevOps记录
  • 解析在OceanBase创建分区的常见问题|OceanBase 用户问题精粹
  • 重温设计模式--职责链模式
  • ctfshow web入门文件上传总结
  • 嵌入式职业规划
  • 2024年科技赋能教育,AI辅导引领新趋势
  • Java实现文件上传功能
  • UE5 猎户座漂浮小岛 02 模型 地形
  • vue3如何运用组合式写法,封装表格列表请求数据的逻辑
  • 【Router】路由器中NAT、NAPT、NPT是什么?
  • [Vue3核心语法] ref、reactive响应式数据
  • 补题:J. Robot Factory
  • 2025选题推荐|基于微信小程序的高校就业招聘系统
  • NumPy 数组操作:从入门到精通
  • Ping百度,出现“ping:baidu.com: Temporary failure in name resolution“解决方案
  • 前端开发攻略---使用css实现滚动吸附效果
  • tortoisegit简单用法
  • 图像识别技术的多领域应用:从医疗到安防
  • 【LeetCode 88. 合并两个有序数组】 java实现
  • 无人机集群路径规划:5种优化算法(SFOA、APO、GOOSE、CO、PIO)求解无人机集群路径规划,提供MATLAB代码
  • 操作系统学习笔记-1.1操作系统的基本概念
  • 抖音大模型面试经历分享
  • docker搭建 Rancher开源的 Kubernetes管理平台
  • C语言中的文件操作:从基础到深入底层原理