当前位置: 首页 > news >正文

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

何为数据代理?

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

要搞懂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 开发中能够更加得心应手地运用这一特性。

相关文章:

  • ANSI C 和 C89/C90
  • Windows 图形显示驱动开发-WDDM 2.0功能_上下文监视
  • C/C++ 知识点:静态语言与动态语言
  • 修改ESP32CAM的示例CameraWebServer里的camera_index.h的方法
  • 软考中级-软件设计师 2022年下半年下午题真题解析:通关秘籍+避坑指南
  • 嵌入式汇编语言从小白到入门:从零开始的底层编程之旅
  • QT Sqlite数据库-教程001 创建数据库和表-下
  • Qt之OpenGL使用Qt封装好的着色器和编译器
  • 【图像分类】【深度学习】图像分类评价指标
  • (区间 dp)洛谷 P1220 关路灯/P2466 Sue 的小球 题解
  • QCustomPlot安装及demo
  • 洛谷 三连击 暴力枚举
  • 如何在 CentOS 7 系统上以容器方式部署 GitLab,使用 ZeroNews 通过互联网访问 GitLab 私有仓库,进行代码版本发布与更新
  • 订单防重复提交与超时取消:AOP + 延迟队列实战
  • Tabnet介绍(Decision Manifolds)和PyTorch TabNet之TabNetRegressor
  • 鼎讯信通 通信安全的终极解决方案:机架式通信干扰机
  • 小白学习java第12天:IO流之缓冲流
  • 数据库守护神-WAL机制
  • 业务幂等性技术架构体系-接口幂等
  • 时序数据异常检测-综述
  • 平谷区住房城乡建设委官方网站/拉新推广赚钱的app
  • 为什么只有中国人怕疫情/网站为什么要seo?
  • phpcms 怎么做视频网站/企业培训计划
  • 北京网站制作设计推广公司/最近一个月的热点事件
  • 企业网站营销的实现方式解读/有哪些营销推广方式
  • wordpress添加商品画廊/东莞seo优化团队