首页 > 其他分享 >proxy代理机制和工作原理,reactive是怎么通过proxy实现响应式的

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

时间:2024-10-14 22:46:24浏览次数:9  
标签:拦截器 target 响应 对象 prop reactive Proxy 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

标签:拦截器,target,响应,对象,prop,reactive,Proxy,proxy
From: https://blog.csdn.net/qq_55018264/article/details/142930873

相关文章

  • FoxyProxy火狐代理插件及BurpSuite代理链设置
    https://www.yisu.com/ask/69767109.htmlBurpsuite小云12972023-09-1204:04:38栏目:编程语言开发者测试专用服务器限时活动,0元免费领,库存有限,领完即止!点击查看>> FoxyProxy是一款功能强大的火狐代理插件,可以帮助用户在浏览器中轻松地切换和管理不同的代理服......
  • 看不懂来打我!让性能提升56%的Vue3.5响应式重构
    前言在Vue3.5版本中最大的改动就是响应式重构,重构后性能竟然炸裂的提升了56%。之所以重构后的响应式性能提升幅度有这么大,主要还是归功于:双向链表和版本计数。这篇文章我们来讲讲使用双向链表后,Vue内部是如何实现依赖收集和依赖触发的。搞懂了这个之后你就能掌握Vue3.5重构后的响......
  • vue3中监视 Reactive对象中的属性
      watch 的第一个参数可以是不同形式的“数据源”:它可以是一个ref(包括计算属性)、一个响应式对象、一个 getter函数、或多个数据源组成的数组一、框架:<template><divclass="divBox"><h2>姓名:{{person.name}}</h2><h2>年龄:{{person.age}}</h2>......
  • 未发表的原创模型!三类典型需求响应负荷的标准化建模+共享储能提升灵活性(Matlab代码实
      ......
  • ProxyPin 抓包,原来可以这么简单!
    ​你是否还在为网络请求的抓包发愁?其实,ProxyPin可以让抓包操作变得异常简单!不需要复杂的设置,也不用繁琐的配置,轻松几步就能实现。让我们一起来看看吧!抓包操作常用于测试网络请求、分析接口响应,那么ProxyPin是如何让这一切变得更简单的呢?它有哪些特色功能,让我们一探究竟。P......
  • 【应急响应+Linux】常见的rootkit隐藏手段:前言
    原文首发在:奇安信攻防社区https://forum.butian.net/share/3796本文主要针对黑灰产相关的蠕木僵毒等恶意软件在Linux上常用的rootkit手段做一些总结,以及详细分析常见应急响应中遇到的进程、文件隐藏手段的原理以及排查和恢复方法;前言本文主要针对黑灰产、以及蠕木僵毒等恶意软......
  • 【应急响应+Linux】常见的rootkit隐藏手段:通过用户层劫持加载器/连接器隐藏进程pld(用
    原理linux在进程启动后,和windows加载dll一样会按照一定的顺序加载动态链接库,相关顺序如下:加载环境变量LD_PRELOAD指定的动态库加载文件/etc/ld.so.preload指定的动态库搜索环境变量LD_LIBRARY_PATH指定的动态库搜索路径搜索路径/lib64下的动态库文件攻击者常见使用的劫......
  • 【应急响应+Linux】常见的rootkit隐藏手段:通过劫持shell环境,实现文件、进程名隐藏等操
    原理修改或构造/etc/profile.d/下sh文件,劫持环境变量,从而实现覆盖常见的命令,如:ps、ls、lsof等;实现:1、配置环境变量shell脚本:重新登录用户之后;或者使用命令source/etc/profile更新配置,使生效;2、根目录下存在的myshell.sh文件被隐藏:执行ls命令效果:排查方法:使用strace......
  • 【应急响应+Linux】常见的rootkit隐藏手段:通过挂载/proc/pid实现pid隐藏
    原理ps、netstat是遍历/proc来显示pid的原理,通过隐藏相关/proc/pid文件夹来实现pid隐藏实现运行如下命令,将pid对应文件夹挂载到隐藏目录上面mount-obind/home/.hidden/proc/9212现象:如下图,使用root权限调用netstat发现PID和Programname都是空:排查方法1、ca......
  • flaks 请求 与 响应 重定向
    请求Request请求 属性ur1完整请求地址base_url去掉GET参数的URLhosturl只有主机和端口号的URLpath路由中的路径method请求方法remote_addr请求的客户端地址argsGET请求参数formPOST请求参数files文件上传headers......