深入理解 Vue 的数据代理机制

news2025/4/18 7:34:28

何为数据代理?

通过一个对象代理对另一个对象中的属性的操作(读/写),就是数据代理。

要搞懂Vue数据代理这个概念,那我们就要从Object.defineProperty()入手

Object.defineProperty()是Vue中比较底层的一个方法,在数据劫持,数据代理以及计算属性等地方都或多或少的用到了本函数

一、认识 Object.defineProperty ()

在前端开发领域,Vue.js 以其简洁易用和高效的响应式数据绑定而备受青睐。其中,数据代理机制是 Vue 实现响应式的核心原理之一。要深入理解 Vue 的数据代理,我们首先得了解 JavaScript 中的一个重要方法 ——Object.defineProperty()。

Object.defineProperty()是 JavaScript 中用于定义或修改对象属性的方法。它允许我们精确地控制对象属性的行为,比如属性的可写性、可枚举性以及是否可配置等。

该方法接收三个参数:​

obj:要定义属性的对象。

prop:要定义或修改的属性的名称。​

descriptor:一个对象,包含了要定义或修改的属性的描述符。

描述符对象可以包含以下属性:​

  • value:属性的值,默认为undefined。​
  • writable:布尔值,表示属性是否可写,默认为false。​
  • enumerable:布尔值,表示属性是否可枚举(即是否能通过for...in循环或Object.keys()等方法被枚举出来),默认为false。​
  • configurable:布尔值,表示属性是否可配置(即是否能被删除或再次修改其描述符),默认为false。​
  • get:一个函数,当访问该属性时会被调用,默认为undefined。​
  • set:一个函数,当设置该属性的值时会被调用,默认为undefined。

1.示例代码

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Object.defineProperty()</title>
</head>

<body>
    <!-- 
        Object.defineProperty()
        1. 这个方法是ES5新增的。
        2. 这个方法的作用是:给对象新增属性,或者设置对象原有的属性。
        3. 怎么用?
            Object.defineProperty(给哪个对象新增属性, '新增的这个属性名叫啥', {给新增的属性设置相关的配置项key:value对})
        4. 第三个参数是属性相关的配置项,配置项都有哪些?每个配置项的作用是啥?
            value 配置项:给属性指定值
            writable 配置项:设置该属性的值是否可以被修改。true表示可以修改。false表示不能修改。
            getter方法 配置项:不需要我们手动调用的。当读取属性值的时候,getter方法被自动调用。
                * getter方法的返回值非常重要,这个返回值就代表这个属性它的值。
            setter方法 配置项:不需要我们手动调用的。当修改属性值的时候,setter方法被自动调用。
                * setter方法上是有一个参数的,这个参数可以接收传过来的值。
            注意:当配置项当中有setter和getter的时候,value和writable配置项都不能存在。
     -->
    <script>

        // 这是一个普通的对象
        let phone = {}

  
        // 给上面的phone对象新增一个color属性
        Object.defineProperty(phone, 'color', {
            value: '太空灰',

        })

    </script>
</body>

</html>

2.writable:布尔值,若为 true,则该属性的值可以被修改,默认是 false

3.get、set

  • get:一个函数,作为该属性的 getter 函数。当访问该属性时,会调用此函数,默认是 undefined
  • set:一个函数,作为该属性的 setter 函数。当为该属性赋值时,会调用此函数,默认是 undefined

 注意:当配置项当中有setter和getter的时候,value和writable配置项都不能存在。

否则报错

在 Vue 的数据代理机制中,getter 和 setter 是自动调用

在get函数多加return '你好世界'

测试set函数,对set的参数做出修改

可以看出setter方法上是有一个参数的,这个参数可以接收传过来的值。

让这两个函数串起来,让其通过set方法获取值,get方法输出值

下面是一个会导致递归的做法

set方法也一样

解决方法:增加临时变量temp

4.ES6新特性:在对象中的函数/方法 :function 是可以省略的。

二、数据代理机制原理

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>数据代理机制</title>
    <script src="../js/vue.js"></script>
</head>

<body>

    <!-- 
        1. 什么是数据代理机制?
            通过访问 代理对象的属性 来间接访问 目标对象的属性。
            数据代理机制的实现需要依靠:Object.defineProperty()方法。
        2. ES6新特性:
            在对象中的函数/方法 :function 是可以省略的。
     -->
    <script>

        // 目标对象
        let target = {
            name: 'zhangsan'
        }

        // 代理对象
        let proxy = {}

        // 如果要实现数据代理机制的话,就需要给proxy新增一个name属性。
        // 注意:代理对象新增的这个属性的名字 和 目标对象的属性名要一致。
        Object.defineProperty(proxy, 'name', {
            // get : function(){
            //     // 间接访问目标对象的属性
            //     return target.name
            // },
            // set : function(val){
            //     target.name = val
            // }

            get() {
                console.log('getter方法执行了@@@@');
                return target.name
            },
            set(val) {
                target.name = val
            }
        })
    
    </script>
</body>

</html>

1.给proxy新增一个name属性。代理对象新增的这个属性的名字 和 目标对象的属性名要一致。

原因:希望访问代理对象的属性的时候,就像访问目标对象的属性一样

2.访问代理对象的属性的时候,返回目标对象的属性(即间接访问目标对象的属性)的代码实现

3.如果给代理对象的属性赋值,希望把目标对象的属性改了的代码实现

4.类比Vue

三、MVVM分层思想

 1. MVVM是什么?

M:Model(模型/数据)
V:View(视图)
VM:ViewModel(视图模型):VM是MVVM中的核心部分。(它起到一个核心的非常重要的作用。)

 MVVM是目前前端开发领域当中非常流行的开发思想。(一种架构模式。)

目前前端的大部分主流框架都实现了这个MVVM思想,例如Vue,React等。

2. Vue框架遵循MVVM吗?

 虽然没有完全遵循 MVVM 模型,但是 Vue 的设计也受到了它的启发。
Vue框架基本上也是符合MVVM思想的。

3. MVVM模型当中倡导了Model和View进行了分离,为什么要分离?

假如Model和View不分离,使用最原始的原生的javascript代码写项目:如果数据发生任意的改动,接下来我们需要编写大篇幅的操作DOM元素的JS代码。

将Model和View分离之后,出现了一个VM核心,这个VM把所有的脏活累活给做了,也就是说,当Model发生改变之后,VM自动去更新View。当View发生改动之后,VM自动去更新Model。我们再也不需要编写操作DOM的JS代码了。开发效率提高了很多。

vue框架就起到了一个VM的作用,监听页面视图的变化,将数据反馈到页面视图上,视图和数据双向绑定。

四、Vue 的数据代理机制​

Vue 的数据代理机制基于Object.defineProperty()实现了数据的响应式。当我们创建一个 Vue 实例时,会传入一个data对象,Vue 会遍历这个data对象的所有属性,并使用Object.defineProperty()将它们转换为响应式数据。​

1.Vue 实例与 data 对象的关系​

在 Vue 中,我们通过new Vue()创建一个 Vue 实例,并传入一个data选项:

let vm = new Vue({
    data: {
        message: 'Hello, Vue!'
    }
});

Vue 会将data对象中的属性代理到 Vue 实例上,使得我们可以通过vm.message来访问和修改data.message的值。这里的代理过程其实就是利用Object.defineProperty()在 Vue 实例上定义了与data对象属性同名的访问器属性。​

2.数据代理的具体实现​

假设我们有如下简单的 Vue 实例:

<div id="app">
    <p>{{ message }}</p>
</div>
<script>
    let app = new Vue({
        el: '#app',
        data: {
            message: '初始消息'
        }
    });
</script>

当 Vue 初始化时,它会遍历data对象的属性,对于message属性,其内部大致实现如下(简化示意,实际 Vue 源码更复杂):

let data = {
    message: '初始消息'
};
let vm = {};
Object.defineProperty(vm,'message', {
    get: function() {
        return data.message;
    },
    set: function(newValue) {
        data.message = newValue;
        // 这里触发视图更新相关操作,Vue会通知依赖该数据的视图进行更新
        console.log('数据已更新,通知视图更新');
    }
});

这样,当我们通过vm.message读取数据时,实际上是读取了data.message的值;当我们通过vm.message修改数据时,不仅data.message的值会改变,Vue 还会触发视图更新操作,从而实现数据与视图的自动同步。​

3.数据代理的优势​

简化数据访问:开发者可以直接通过 Vue 实例访问和修改数据,无需像传统 JavaScript 那样通过复杂的对象层级去访问。例如vm.message比this.$data.message(在 Vue 中也可访问,但相对繁琐)更简洁直观。​

实现响应式更新:通过Object.defineProperty()的getter和setter,Vue 能够监听数据的变化,一旦数据发生改变,立即自动更新与之关联的视图,大大提高了开发效率,减少了手动操作 DOM 更新视图的代码量。

五、总结​

Vue 的数据代理机制巧妙地利用了 JavaScript 的Object.defineProperty()方法,将data对象的属性代理到 Vue 实例上,实现了简洁高效的数据访问和强大的响应式更新功能。深入理解这一机制,有助于我们更好地编写 Vue 应用,优化代码结构,提升开发体验。无论是构建小型的交互组件,还是大型的单页应用,Vue 的数据代理机制都为我们提供了坚实的基础,让我们能够专注于业务逻辑的实现,而无需过多关注数据与视图同步的底层细节。​

希望通过本文的介绍,你对 Vue 的数据代理机制有了更清晰的认识,在今后的 Vue 开发中能够更加得心应手地运用这一特性。

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

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

相关文章

Java excel导入/导出导致内存溢出问题,以及解决方案

excel导入/导出导致内存溢出问题&#xff0c;以及解决方案 1、内存溢出问题导入功能重新修正&#xff0c;采用SAX的流式解析数据。并结合业务流程。导出功能&#xff1a;由于精细化了业务流程&#xff0c;导致比较代码比较冗杂&#xff0c;就只放出最简单的案例。 1、内存溢出问…

10 个最新 CSS 功能已在所有主流浏览器中得到支持

前言 CSS 不断发展&#xff0c;新功能使我们的工作更快、更简洁、更强大。得益于最新的浏览器改进&#xff08;Baseline 2024&#xff09;&#xff0c;许多新功能现在可在所有主要引擎上使用。以下是您可以立即开始使用的10 CSS新功能。 1. Scrollbar-Gutter 和 Scrollbar-Co…

思科模拟器的单臂路由,交换机,路由器,路由器只要两个端口的话,连接三台电脑该怎么办,划分VLAN,dotlq协议

单臂路由 1. 需求&#xff1a;让三台电脑互通 2. 在二层交换机划分vlan&#xff0c;并加入&#xff1b; 3. 将连接二层交换机和路由器的端口f0/4改为trunk模式 4. 路由器&#xff1a;进入连接路由器的f0/0端口将端口开启 5. 进入每个vlan设dotlq协议并设网络IP&#xff08…

14 nginx 的 dns 缓存的流程

前言 这个是 2020年11月 记录的这个关于 nginx 的 dns 缓存的问题 docker 环境下面 前端A连到后端B 前端B连到后端A 最近从草稿箱发布这个问题的时候, 重新看了一下 发现该问题的记录中仅仅是 定位到了 nginx 这边的 dns 缓存的问题, 但是 并没有到细节, 没有到 具体的 n种…

实战教程:使用JetBrians Rider快速部署与调试PS5和Xbox上的UE项目

面向主机游戏开发者的重大新闻&#xff01;在2024.3版本中&#xff0c;JetBrains Rider 增加了对 PlayStation5 和 Xbox 游戏主机的支持&#xff0c;您可以直接在您喜欢的游戏主机上构建、部署和调试 Unreal Engine 和自定义游戏引擎。 JetBrains Rider现在支持主机游戏开发&am…

专题十五:动态路由——BGP

一、BGP的基本概念 BGP&#xff08;Border Gateway Protocol&#xff0c;边界网关协议&#xff09;是一种用于在不同自治系统&#xff08;AS&#xff09;之间交换路由信息的外部网关协议&#xff08;EGP&#xff09;。通过TCP179端口建立连接。目前采用BGP4版本&#xff0c;IP…

hive数仓要点总结

1.OLTP和OLAP区别 OLTP&#xff08;On-Line Transaction Processing&#xff09;即联机事务处理&#xff0c;也称为面向交易的处理过程&#xff0c;其基本特征是前台接收的用户数据可以立即传送到计算中心进行处理&#xff0c;并在很短的时间内给出处理结果&#xff0c;是对用…

git安装(windows)

通过网盘分享的文件&#xff1a;资料(1) 链接: https://pan.baidu.com/s/1MAenYzcQ436MlKbIYQidoQ 提取码: evu6 点击next 可修改安装路径 默认就行 一般从命令行调用&#xff0c;所以不用创建。 用vscode&#xff0c;所以这么选择。

微信小程序实战案例 - 餐馆点餐系统 阶段1 - 菜单浏览

阶段 1 – 菜单浏览&#xff08;超详细版&#xff09; 目标&#xff1a;完成「首页&#xff1d;菜品卡片列表」 打好 UI 地基会从 云数据库 拉取 categories / dishes 并渲染打 Git Tag v1.0‑menu 1. 技术/知识点速览 知识点关键词说明云数据库db.collection().where().…

Dashboard的安装和基本使用

1.Dashboard简介&#xff1a; Dashboard是Kubernetes的Web图形用户界面&#xff08;GUI&#xff09;&#xff0c;它为用户提供了一个直观的方式来管理和监控Kubernetes集群。 2.实验基础和前置条件&#xff1a; 本实验以Kubernetes集群环境搭建与初始化-CSDN博客为基础和前置…

英语单词 list 11

前言 这一个 list 是一些简单的单词。感觉这个浏览单词的方法比较低效&#xff0c;所以准备每天最多看一个 list &#xff0c;真要提升英语水平&#xff0c;感觉还是得直接做阅读理解题。就像我们接触中文阅读材料一样&#xff0c;当然光知道这个表面意思还不够&#xff0c;还…

通义灵码助力Neo4J开发:快速上手与智能编码技巧

在 Web 应用开发中&#xff0c;Neo4J 作为一种图数据库&#xff0c;用于存储节点及节点间的关系。当图结构复杂化时&#xff0c;关系型数据库的查找效率会显著降低&#xff0c;甚至无法有效查找&#xff0c;这时 Neo4J 的优势便凸显出来。然而&#xff0c;由于其独特的应用场景…

高性能文件上传服务

高性能文件上传服务 —— 您业务升级的不二选择 在当今互联网数据量激增、文件体积日益庞大的背景下&#xff0c;高效、稳定的文件上传方案显得尤为重要。我们的文件分块上传服务端采用业界领先的 Rust HTTP 框架 Hyperlane 开发&#xff0c;凭借其轻量级、低延时和高并发的特…

Java Lambda 表达式详解:发展史、语法、使用场景及代码示例

Java Lambda 表达式详解&#xff1a;发展史、语法、使用场景及代码示例 1. Lambda 表达式的发展史 背景与动机 JDK 7 前&#xff1a;Java的匿名内部类虽强大&#xff0c;但代码冗余&#xff08;如事件监听器、集合遍历&#xff09;。JDK 8&#xff08;2014&#xff09;&#…

【从0到1学Elasticsearch】Elasticsearch从入门到精通(下)

我们在【从0到1学Elasticsearch】Elasticsearch从入门到精通&#xff08;上&#xff09;这边文章详细讲解了如何创建索引库和文档及javaAPI操作&#xff0c;但是在实战当中&#xff0c;我们还需要根据一些特殊字段对文档进行查找搜索&#xff0c;仅仅靠id查找文档是显然不够的。…

Python实现贪吃蛇二

上篇文章Python实现贪吃蛇一&#xff0c;实现了一个贪吃蛇的基础版本&#xff0c;但存在一些不足&#xff0c;也缺乏一些乐趣。本篇文章将对其进行一些改进&#xff0c;主要修改/实现以下几点&#xff1a; 1、解决食物随机生成的位置与蛇身重合问题 2、蛇身移动加速/减速功能 3…

基于51单片机的正负5V数字电压表( proteus仿真+程序+设计报告+讲解视频)

基于51单片机的正负5V数字电压表( proteus仿真程序设计报告讲解视频&#xff09; 仿真图proteus7.8及以上 程序编译器&#xff1a;keil 4/keil 5 编程语言&#xff1a;C语言 设计编号&#xff1a;S0101 1. 主要功能&#xff1a; 设计一个基于51单片机数字电压表 1、能够…

Java雪花算法

以下是用Java实现的雪花算法代码示例&#xff0c;包含详细注释和异常处理&#xff1a; 代码下面有解析 public class SnowflakeIdGenerator {// 起始时间戳&#xff08;2020-01-01 00:00:00&#xff09;private static final long START_TIMESTAMP 1577836800000L;// 各部分…

前端大屏可视化项目 局部全屏(指定盒子全屏)

需求是这样的&#xff0c;我用的项目是vue admin 项目 现在需要在做大屏项目 不希望显示除了大屏的其他东西 于是想了这个办法 至于大屏适配问题 请看我文章 底部的代码直接复制就可以运行 vue2 px转rem 大屏适配方案 postcss-pxtorem-CSDN博客 <template><div …

01_JDBC

文章目录 一、概述1.1、什么是JDBC1.2、JDBC原理 二、JDBC入门2.1、准备工作2.1.1、建库建表2.1.2、新建项目 2.2、建立连接2.2.1、准备四大参数2.2.2、加载驱动2.2.3、准备SQL语句2.2.4、建立连接2.2.5、常见问题 2.3、获取发送SQL的对象2.4、执行SQL语句2.5、处理结果2.6、释…