欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 教育 > 锐评 > proxy代理机制和工作原理,reactive是怎么通过proxy实现响应式的

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

2024/10/24 5:15:44 来源:https://blog.csdn.net/qq_55018264/article/details/142930873  浏览:    关键词: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

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com