前端Vue篇之双向数据绑定的原理、使用 Object.defineProperty() 来进行数据劫持有什么缺点?

本文主要是介绍前端Vue篇之双向数据绑定的原理、使用 Object.defineProperty() 来进行数据劫持有什么缺点?,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

  • 双向数据绑定的原理
    • 数据劫持
    • 模板解析
    • 订阅者
    • MVVM整合
  • 使用 Object.defineProperty() 来进行数据劫持有什么缺点?


双向数据绑定的原理

双向数据绑定是一种数据驱动的编程模式,它将视图层和数据模型层进行了双向绑定,当数据模型层的数据发生变化时,视图层的数据也会随之更新,反之亦然。

在前端框架中,双向数据绑定的实现原理通常是通过数据劫持和发布/订阅模式来实现的。当数据模型层的数据发生变化时,会触发一个更新视图的操作,这个操作会通知所有订阅了这个数据的视图进行更新。反之,当视图层的数据发生变化时,也会触发一个更新数据模型的操作,这个操作会通知所有订阅了这个数据的数据模型进行更新。

这样,无论是数据模型层的数据发生变化,还是视图层的数据发生变化,都会自动地更新另一层的数据,实现了数据模型层和视图层的双向绑定。

在Vue.js中,双向数据绑定的原理基于数据劫持结合发布者-订阅者模式。以下是详细的步骤:

  1. 数据劫持:首先,需要对要观察(observe)的数据对象进行递归遍历,包括子属性对象的属性,都加上 setter 和 getter。这样给这个对象的某个值赋值就会触发 setter,从而能够监听到数据变化。

  2. 模板解析:在编译(compile)阶段,Vue.js会解析模板指令,将模板中的变量替换成数据,并初始化渲染页面视图。每个指令对应的节点都会被绑定更新函数,同时添加监听数据的订阅者。一旦数据有变动,收到通知后会更新视图。

  3. 订阅者:Watcher作为订阅者是Observer和Compile之间通信的桥梁。它的主要作用包括:① 在自身实例化时往属性订阅器(dep)里面添加自己; ② 必须有一个 update() 方法; ③ 待属性变动时,能调用自身的 update() 方法,并触发 Compile 中绑定的回调。

  4. MVVM整合:MVVM作为数据绑定的入口,整合了Observer、Compile和Watcher三者。通过Observer来监听自己的model数据变化,通过Compile来解析编译模板指令。最终利用Watcher搭起Observer和Compile之间的通信桥梁,实现数据变化时的视图更新以及视图交互变化时的数据 model 变更,实现双向绑定效果。

总体来说,双向数据绑定机制允许视图层和数据层之间的同步更新。在 Vue 和其他类似框架中,双向数据绑定的实现原理通常基于初始化、视图监听器、数据监听器和反向更新这些步骤,形成一个闭环,确保数据模型和视图之间的双向同步。

数据劫持

数据劫持是一种编程技术,用于在数据被读取或修改时执行一些额外的操作。在JavaScript中,数据劫持通常通过使用Object.definePropertyProxy对象来实现。

例如,我们可以使用Object.defineProperty来劫持一个对象的属性:

let obj = { name: 'Alice' };Object.defineProperty(obj, 'name', {get: function() {console.log('Name has been read');return this._name;},set: function(value) {console.log('Name has been set');this._name = value;}
});obj.name = 'Bob'; // 输出: "Name has been set"
console.log(obj.name); // 输出: "Name has been read", "Bob"

在这个例子中,我们劫持了obj对象的name属性,当name属性被读取或设置时,会执行我们定义的getset方法。

数据劫持在实现双向数据绑定和响应式系统时非常有用,因为它允许我们在数据被读取或修改时执行一些额外的操作,例如更新视图或触发事件。

在Vue.js中,数据劫持是通过使用Object.definePropertyProxy对象来实现的。Vue.js使用数据劫持来实现其响应式系统,这是Vue.js实现双向数据绑定的关键。

当你在Vue.js中创建一个数据对象时,Vue.js会遍历这个对象的所有属性,使用Object.definePropertyProxy对象来劫持这些属性。当这些属性被读取或修改时,Vue.js会执行一些额外的操作,例如更新视图或触发事件。

例如,当你在Vue.js中创建一个数据对象时:

let vm = new Vue({data: {name: 'Alice'}
});

Vue.js会劫持vm对象的name属性,当name属性被读取或修改时,Vue.js会执行一些额外的操作。

这样,无论是数据模型层的数据发生变化,还是视图层的数据发生变化,都会自动地更新另一层的数据,实现了数据模型层和视图层的双向绑定。

模板解析

在Vue.js中,模板解析是指将Vue.js的模板语法解析为JavaScript代码的过程。Vue.js的模板语法允许你在HTML模板中使用JavaScript表达式,指令和插值,这些都需要在运行时被解析为JavaScript代码。

例如,当你在Vue.js的模板中使用插值({{ }})时,这个插值会被解析为一个JavaScript表达式:

<div id="app">{{ message }}
</div>

在这个例子中,{{ message }}会被解析为_v(_s(message)),其中_v是一个函数,用于创建一个文本节点,_s是一个函数,用于转义特殊字符。

模板解析是Vue.js实现其响应式系统的关键,因为它允许你在模板中使用JavaScript表达式,指令和插值,这些都需要在运行时被解析为JavaScript代码。

订阅者

在Vue.js中,订阅者是指那些订阅了数据变化的对象。当数据发生变化时,订阅者会被通知,然后它们可以执行一些操作,例如更新视图。

在Vue.js的响应式系统中,订阅者通常是指那些使用了数据劫持的对象。当一个属性被劫持后,Vue.js会为这个属性创建一个订阅者列表,然后当这个属性的值发生变化时,Vue.js会遍历这个订阅者列表,通知所有的订阅者。

例如,当你在Vue.js中创建一个数据对象时:

let vm = new Vue({data: {name: 'Alice'}
});

Vue.js会为vm对象的name属性创建一个订阅者列表,然后当name属性的值发生变化时,Vue.js会遍历这个订阅者列表,通知所有的订阅者。

MVVM整合

MVVM是Model-View-ViewModel的缩写,是一种软件架构模式,它将应用程序分为三个部分:模型(Model)、视图(View)和视图模型(ViewModel)。在MVVM中,视图模型是视图和模型之间的中介,它负责处理视图的显示逻辑和用户输入,同时也负责从模型中获取数据。

在Vue.js中,MVVM是通过Vue实例来实现的。Vue实例是一个MVVM模式的实现,它将模板(View)和数据(Model)绑定在一起,同时也提供了一些方法和属性来处理视图的显示逻辑和用户输入(ViewModel)。

例如,当你在Vue.js中创建一个Vue实例时:

let vm = new Vue({el: '#app',data: {message: 'Hello Vue.js!'}
});

这个Vue实例就是一个MVVM模式的实现。它将模板(View)和数据(Model)绑定在一起,同时也提供了一些方法和属性来处理视图的显示逻辑和用户输入(ViewModel)。

总的来说,MVVM是一种非常强大的软件架构模式,它可以帮助你更好地组织和管理你的代码,同时也可以提高你的代码的可维护性和可测试性。

使用 Object.defineProperty() 来进行数据劫持有什么缺点?

使用 Object.defineProperty() 进行数据劫持存在以下一些缺点:

  1. 无法监听数组的变化Object.defineProperty() 只能劫持对象的属性,对于数组,它无法直接监听数组内部元素的变化,例如通过索引修改数组元素的值或者使用 push、pop 等方法改变数组长度。

  2. 初始遍历开销大:在初始化时,需要递归遍历所有的属性并使用 Object.defineProperty() 进行劫持,这会导致初始遍历的开销较大。

  3. 只能监听属性的变化Object.defineProperty() 只能劫持对象的属性,无法劫持整个对象的变化。如果要深度监听对象,需要遍历对象的每个属性进行劫持。

  4. 兼容性问题:在一些旧版本的浏览器中,Object.defineProperty() 的兼容性可能存在问题,限制了其在某些环境下的应用。

因为上述缺点,Vue 在新版本中采用了更高效的数据劫持方式,例如使用 ES6 中的 Proxy 对象来代替 Object.defineProperty(),以解决这些问题。Proxy 对象可以更灵活地监听对象的操作,并且能够监听数组的变化,提高了数据劫持的效率和功能性。在 Vue 3.0 中已经不再使用 Object.defineProperty() 这种方式,而是通过使用 Proxy 对象进行代理,从而实现数据劫持。 Proxy 能够完美监听到任何方式的数据改变,但唯一的缺点是兼容性的问题,因为 Proxy 是 ES6 的语法。

持续学习总结记录中,回顾一下上面的内容:
双向数据绑定的原理就是通过数据劫持和模板解析来实现的。这样无论是数据模型的数据发生变化,还是视图的数据发生变化,都会自动地更新另一层的数据。使用 Object.defineProperty() 进行数据劫持的主要缺点是它只能劫持对象的属性,而不能劫持对象本身或数组的变化。这意味着如果你想劫持一个对象或数组,你需要为它的每个属性或元素都添加一个 getter 和 setter,这会导致代码变得复杂和难以维护。

这篇关于前端Vue篇之双向数据绑定的原理、使用 Object.defineProperty() 来进行数据劫持有什么缺点?的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/714069

相关文章

python中的显式声明类型参数使用方式

《python中的显式声明类型参数使用方式》文章探讨了Python3.10+版本中类型注解的使用,指出FastAPI官方示例强调显式声明参数类型,通过|操作符替代Union/Optional,可提升代... 目录背景python函数显式声明的类型汇总基本类型集合类型Optional and Union(py

MySQL中查询和展示LONGBLOB类型数据的技巧总结

《MySQL中查询和展示LONGBLOB类型数据的技巧总结》在MySQL中LONGBLOB是一种二进制大对象(BLOB)数据类型,用于存储大量的二进制数据,:本文主要介绍MySQL中查询和展示LO... 目录前言1. 查询 LONGBLOB 数据的大小2. 查询并展示 LONGBLOB 数据2.1 转换为十

Java使用正则提取字符串中的内容的详细步骤

《Java使用正则提取字符串中的内容的详细步骤》:本文主要介绍Java中使用正则表达式提取字符串内容的方法,通过Pattern和Matcher类实现,涵盖编译正则、查找匹配、分组捕获、数字与邮箱提... 目录1. 基础流程2. 关键方法说明3. 常见场景示例场景1:提取所有数字场景2:提取邮箱地址4. 高级

使用SpringBoot+InfluxDB实现高效数据存储与查询

《使用SpringBoot+InfluxDB实现高效数据存储与查询》InfluxDB是一个开源的时间序列数据库,特别适合处理带有时间戳的监控数据、指标数据等,下面详细介绍如何在SpringBoot项目... 目录1、项目介绍2、 InfluxDB 介绍3、Spring Boot 配置 InfluxDB4、I

使用Java读取本地文件并转换为MultipartFile对象的方法

《使用Java读取本地文件并转换为MultipartFile对象的方法》在许多JavaWeb应用中,我们经常会遇到将本地文件上传至服务器或其他系统的需求,在这种场景下,MultipartFile对象非... 目录1. 基本需求2. 自定义 MultipartFile 类3. 实现代码4. 代码解析5. 自定

使用Python实现无损放大图片功能

《使用Python实现无损放大图片功能》本文介绍了如何使用Python的Pillow库进行无损图片放大,区分了JPEG和PNG格式在放大过程中的特点,并给出了示例代码,JPEG格式可能受压缩影响,需先... 目录一、什么是无损放大?二、实现方法步骤1:读取图片步骤2:无损放大图片步骤3:保存图片三、示php

使用Python实现一个简易计算器的新手指南

《使用Python实现一个简易计算器的新手指南》计算器是编程入门的经典项目,它涵盖了变量、输入输出、条件判断等核心编程概念,通过这个小项目,可以快速掌握Python的基础语法,并为后续更复杂的项目打下... 目录准备工作基础概念解析分步实现计算器第一步:获取用户输入第二步:实现基本运算第三步:显示计算结果进

MySQL按时间维度对亿级数据表进行平滑分表

《MySQL按时间维度对亿级数据表进行平滑分表》本文将以一个真实的4亿数据表分表案例为基础,详细介绍如何在不影响线上业务的情况下,完成按时间维度分表的完整过程,感兴趣的小伙伴可以了解一下... 目录引言一、为什么我们需要分表1.1 单表数据量过大的问题1.2 分表方案选型二、分表前的准备工作2.1 数据评估

Python中的filter() 函数的工作原理及应用技巧

《Python中的filter()函数的工作原理及应用技巧》Python的filter()函数用于筛选序列元素,返回迭代器,适合函数式编程,相比列表推导式,内存更优,尤其适用于大数据集,结合lamb... 目录前言一、基本概念基本语法二、使用方式1. 使用 lambda 函数2. 使用普通函数3. 使用 N

python之uv使用详解

《python之uv使用详解》文章介绍uv在Ubuntu上用于Python项目管理,涵盖安装、初始化、依赖管理、运行调试及Docker应用,强调CI中使用--locked确保依赖一致性... 目录安装与更新standalonepip 安装创建php以及初始化项目依赖管理uv run直接在命令行运行pytho