自学内容网 自学内容网

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

原文地址:https://blog.csdn.net/qq_55018264/article/details/142930873

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!