vue 中的数据代理

在 Vue 中,数据代理(Data Proxy) 是 Vue 实现 MVVM 模式 的关键技术之一。Vue 使用数据代理让你可以通过 this.message 访问 data.message,而不需要写 this.data.message —— 这大大简化了模板和逻辑代码。

我们来深入理解它的本质、实现原理和源码体现。

🔹 什么是数据代理?

Vue 实例将 data、props、computed 等属性“代理”到 vm(Vue 实例)自身上,从而让我们能直接通过 this.xx 访问,而不必每次访问 this._data.xx。

✅ 示例:数据代理的使用效果

const vm = new Vue({data: {message: 'hello'}
})console.log(vm.message) // 实际上是 vm._data.message

🧠 数据代理的实现原理(以 Vue 2 为例)

Vue 2 中通过 Object.defineProperty 实现数据代理。

👉 源码简化模拟:

function proxy(target, sourceKey, key) {Object.defineProperty(target, key, {get() {return target[sourceKey][key]},set(val) {target[sourceKey][key] = val}})
}

Vue 实例化时,会遍历 data 中的所有属性,调用 proxy(vm, ‘_data’, key) 将它们挂载到实例 vm 上。

🔧 Vue 2 中相关源码(core/instance/state.js)

function initData(vm) {const data = vm.$options.datavm._data = typeof data === 'function' ? data.call(vm, vm) : data || {}// 数据代理const keys = Object.keys(vm._data)let i = keys.lengthwhile (i--) {proxy(vm, '_data', keys[i])}observe(vm._data)
}

📌 Vue 3 的处理方式

Vue 3 中由于响应式改为使用 Proxy,所以数据代理并不是必须通过 defineProperty 显式定义,而是由 reactive() 和 ref() 本身提供的响应式代理能力。

import { reactive } from 'vue'const state = reactive({ count: 0 })console.log(state.count) // 已被代理,无需显式挂载到组件实例上

Vue 3 更加模块化,组件实例并不自动把数据代理到 this 上,尤其在

🧠 为什么要用数据代理?

简化访问:

  • 不用写 this._data.xxx,直接 this.xxx

实现双向绑定:

  • v-model 语法简洁,背后依赖于代理 + 响应式

方便调试和语法提示:

  • IDE 能提示实例属性;不用深层嵌套对象路径

🔄 数据代理 vs 响应式代理

特性数据代理响应式代理
实现技术Object.defineProperty(Vue 2)Proxy(Vue 3)
目的让你能通过 this.key 访问 data.key追踪依赖、触发视图更新
是否双向绑定否,单纯转发 getter/setter是,配合响应式系统自动更新视图
使用位置Vue 实例、组件所有响应式状态(ref、reactive)

✅ 小结

  • 数据代理是为了简化访问方式,不是响应式的根本机制。
  • Vue 2 中通过 Object.defineProperty 将 data 的属性代理到 Vue 实例上。
  • Vue 3 中响应式是通过 Proxy 实现,数据代理的需求被弱化(但原理仍然存在)。
  • 它是 MVVM 中 ViewModel 作为桥梁的一部分。

小型 Vue 响应式系统(含数据代理)

// 1. 数据代理
function proxy(vm, sourceKey, key) {Object.defineProperty(vm, key, {get() {return vm[sourceKey][key]},set(val) {vm[sourceKey][key] = val}})
}// 2. 响应式转换(核心 Observer)
function defineReactive(obj, key, val) {const dep = new Dep()Object.defineProperty(obj, key, {get() {dep.depend()return val},set(newVal) {val = newValdep.notify()}})
}// 3. 对整个 data 对象做响应式处理
function observe(obj) {Object.keys(obj).forEach(key => defineReactive(obj, key, obj[key]))
}// 4. 依赖收集器
class Dep {constructor() {this.subscribers = new Set()}depend() {if (activeEffect) {this.subscribers.add(activeEffect)}}notify() {this.subscribers.forEach(effect => effect())}
}let activeEffect = null
function watchEffect(effect) {activeEffect = effecteffect() // 立即执行一次activeEffect = null
}// 5. 模拟 Vue 实例
function Vue(options) {this._data = options.dataobserve(this._data)// 代理 _data 到 thisObject.keys(this._data).forEach(key => {proxy(this, '_data', key)})
}
// 创建 Vue 实例
const vm = new Vue({data: {message: 'Hello',count: 1}
})// 绑定“视图更新”逻辑
watchEffect(() => {console.log('视图更新:', vm.message, vm.count)
})// 修改数据,自动触发“视图更新”
vm.message = 'Hello Vue'
vm.count++

Vue 3 响应式系统简易实现(模拟核心功能)

// 1. 依赖收集器
const targetMap = new WeakMap()
let activeEffect = nullfunction track(target, key) {if (!activeEffect) returnlet depsMap = targetMap.get(target)if (!depsMap) {depsMap = new Map()targetMap.set(target, depsMap)}let deps = depsMap.get(key)if (!deps) {deps = new Set()depsMap.set(key, deps)}deps.add(activeEffect)
}function trigger(target, key) {const depsMap = targetMap.get(target)if (!depsMap) returnconst deps = depsMap.get(key)if (deps) {deps.forEach(effect => effect())}
}// 2. 创建响应式对象
function reactive(target) {return new Proxy(target, {get(obj, key) {track(obj, key)return Reflect.get(obj, key)},set(obj, key, value) {const result = Reflect.set(obj, key, value)trigger(obj, key)return result}})
}// 3. 注册副作用(自动运行函数)
function effect(fn) {activeEffect = fnfn()activeEffect = null
}
const state = reactive({count: 0,name: 'Vue3'
})effect(() => {console.log('视图更新:', state.count, state.name)
})state.count++     // 触发更新
state.name = 'Vue3 Proxy'

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/905113.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于Python的网络电子书阅读系统

标题:基于Python的网络电子书阅读系统 内容:1.摘要 随着数字化阅读的兴起,网络电子书阅读需求日益增长。本研究旨在开发一个基于Python的网络电子书阅读系统,以满足用户便捷阅读电子书的需求。采用Python的Flask框架搭建Web服务器,结合SQLit…

基于SpringBoot的抽奖系统测试报告

一、编写目的 本报告为抽奖系统测试报告,本项目可用于团体抽奖活动,包括了用户注册,用户登录,修改奖项以及抽奖等功能。 二、项目背景 抽奖系统采用前后端分离的方法来实现,同时使用了数据库来存储相关的数据&…

Apache Flink 与 Flink CDC:概念、联系、区别及版本演进解析

Apache Flink 与 Flink CDC:概念、联系、区别及版本演进解析 在实时数据处理和流式计算领域,Apache Flink 已成为行业标杆。而 Flink CDC(Change Data Capture) 作为其生态中的重要组件,为数据库的实时变更捕获提供了强大的能力。 本文将从以下几个方面进行深入讲解: 什…

单片机-STM32部分:9、定时器

飞书文档https://x509p6c8to.feishu.cn/wiki/A749wx8T0ioqfgkzZKlc9poknUf SMT32F1系列共有8个定时器: 基本定时器(TIM6、TIM7) 通用定时器(TIM2、TIM3、TIM4、TIM5) 高级定时器(TIM1、TIM8&#xff09…

uniapp-商城-51-后台 商家信息(logo处理)

前面对页面基本进行了梳理和说明,特别是对验证规则进行了阐述,并对自定义规则的兼容性进行了特别补充,应该说是干货满满。不知道有没有小伙伴已经消化了。 下面我们继续前进,说说页面上的logo上传组件,主要就是uni-fil…

ideal创建Springboot项目(Maven,yml)

以下是使用 IntelliJ IDEA 创建基于 Maven 的 Spring Boot 项目并使用 YAML 配置文件的详细步骤: 一、创建 Spring Boot 项目 启动项目创建向导 打开 IntelliJ IDEA,点击“File”->“New”->“Project”。 在弹出的“New Project”窗口中&#…

MATLAB中矩阵和数组的区别

文章目录 前言环境配置1. 数据结构本质2. 运算规则(1)基本运算(2)特殊运算 3. 函数与操作4. 高维支持5. 创建方式 前言 在 MATLAB 中,矩阵(Matrix) 和 数组(Array) 的概…

iTwin 数据报表(只是简单的原型不代表实现)

大概想法是 前端从schema和class中选中感兴趣的property内容生成ecsql语句传递给后端后端解析ecsql并提供公开接口给各个分析工具,如excel,poewerBI等(Odata或者直接选择来自网站)再由分析工具做进一步的处 还未想好的点 如何存…

Spring AI 系列——使用大模型对文本内容分类归纳并标签化输出

原理概述 利用大语言模型(LLM)实现文本分类,核心思想是通过预训练模型理解输入文本的语义,并将其映射到预先定义好的分类标签。在这个过程中,我们借助 Spring AI Alibaba 提供的能力,使用阿里云 DashScope…

LeetCode 高频题实战:如何优雅地序列化和反序列化字符串数组?

文章目录 摘要描述题解答案题解代码分析编码方法解码方法 示例测试及结果时间复杂度空间复杂度总结 摘要 在分布式系统中,数据的序列化与反序列化是常见的需求,尤其是在网络传输、数据存储等场景中。LeetCode 第 271 题“字符串的编码与解码”要求我们设…

GitHub打开缓慢甚至失败的解决办法

在C:\Windows\System32\drivers\etc的hosts中增加如下内容: 20.205.243.166 github.com 199.59.149.236 github.global.ssl.fastly.net185.199.109.153 http://assets-cdn.github.com 185.199.108.153 http://assets-cdn.github.com 185.199.110.153 http://asset…

重生之我在2024学Fine-tuning

一、Fine-tuning(微调)概述 Fine-tuning(微调)是机器学习和深度学习中的一个重要概念,特别是在预训练模型的应用上。它指的是在模型已经通过大量数据训练得到一个通用的预训练模型后,再针对特定的任务或数据…

计算机网络 4-2-1 网络层(IPv4)

2 IPv4分组 各协议之间的关系 IP协议(Internet Protocol, 网际协议)是互联网的核心&#xff01; ARP协议用于查询同一网络中的<主机IP地址&#xff0c;MAC地址>之间的映射关系 ICMP协议用于网络层实体之间相互通知“异常事件” IGMP协议用于实现IP组播 2.1 结构<首…

Docker中运行的Chrome崩溃问题解决

问题 各位看官是否在 Docker 容器中的 Linux 桌面环境&#xff08;如Xfce&#xff09;上启动Chrome &#xff0c;遇到了令人沮丧的频繁崩溃问题&#xff1f;尤其是在打开包含图片、视频的网页&#xff0c;或者进行一些稍复杂的操作时&#xff0c;窗口突然消失&#xff1f;如果…

K8S cgroups详解

以下是 Kubernetes 中 cgroups&#xff08;Control Groups&#xff09; 的详细解析&#xff0c;涵盖其核心原理、在 Kubernetes 中的具体应用及实践操作&#xff1a; 一、cgroups 基础概念 1. 是什么&#xff1f; cgroups 是 Linux 内核提供的 资源隔离与控制机制&#xff0c…

javaer快速从idea转战vscode

插件安装列表 在插市场安装下面插件 Extension Pack for JavaSpring Boot Tools 配置文件提示Database Client Database/No-SQL管理工具httpYac - Rest Client .http文件编辑、API测试工具 https://httpyac.github.io/guide/request.htmlGit Graph 图形化Git工具XML by Red H…

[项目总结] 抽奖系统项目技术应用总结

&#x1f338;个人主页:https://blog.csdn.net/2301_80050796?spm1000.2115.3001.5343 &#x1f3f5;️热门专栏: &#x1f9ca; Java基本语法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12615970.html?spm1001.2014.3001.5482 &#x1f355; Collection与…

【赵渝强老师】TiDB SQL层的工作机制

TiDB节点的SQL层&#xff0c;即TiDB Server&#xff0c;它负责将SQL翻译成Key-Value操作&#xff0c;将其转发给共用的分布式Key-Value存储层TiKV&#xff0c;然后组装TiKV返回的结果&#xff0c;最终将查询结果返回给客户端。这一层的节点都是无状态的&#xff0c;节点本身并不…

性能远超SAM系模型,苏黎世大学等开发通用3D血管分割基础模型

如果把人的身体比作一座庞大的城市&#xff0c;那么血管无疑就是这座城市的「道路」&#xff0c;动脉、静脉以及毛细血管对应着高速公路、城市道路以及乡间小道&#xff0c;它们相互协作&#xff0c;通过血液将营养物质、氧气等输送到身体各处&#xff0c;从而维持着这座「城市…

git高效杀器——cz-customizable 搭配 commitlint

What is cz-customizable and commitlint? cz-customizable 一款可定制化的Commitizen插件(也可作为独立工具),旨在帮助创建如约定式提交规范的一致性提交消息。commitlint commitlint 是一个用于检查 Git 提交信息的工具,它可以帮助开发者保持提交信息的规范性和一致性。…