Vue2和vue3中双向数据绑定的原理,ES6的Proxy对象代理和JavaScript的Object.defineProperty,使用详细

简介:Object.defineProperty大家都知道,是vue2中双向数据绑定的原理,它是 JavaScript 中一个强大且常用的方法,用于定义对象属性,允许我们精确地控制属性的行为,包括读取、写入和删除等操作;

而Proxy是vue3中双向数据绑定的原理,是ES6中一种用于创建代理对象的特殊对象,它允许我们拦截并自定义目标对象的操作,例如属性访问、赋值、函数调用等。Proxy提供了一种机制,可以在目标对象上设置拦截器,从而拦截对目标对象的操作。

一、Object.defineProperty

1、Object.defineProperty是一个用于定义或修改对象属性的方法,可以精确地控制属性的行为,例如可写性、可枚举性和可配置性;在Object.defineProperty 方法中,有三个必需的参数和一个可选的第四参数。

  1. obj (必需):要定义属性的对象。可以是任何 JavaScript 对象。
  2. prop (必需):要定义或修改的属性的名称。可以是一个字符串,表示属性的名称。
  3. descriptor (必需):一个对象,用于定义或修改属性的特性。

还可以包含以下可选的属性:

- configurable (可选):布尔值,表示该属性是否可以被删除或修改特性。默认为 false。

- enumerable (可选):布尔值,表示该属性是否可以在 for...in 循环中被枚举。默认为 false。

- value (可选):任意类型的值,表示属性的初始值。默认为 undefined。

- writable (可选):布尔值,表示该属性的值是否可以被修改。默认为 false。

- get (可选):函数,表示获取属性值时要调用的函数。

- set (可选):函数,表示设置属性值时要调用的函数。

2、基本语法(多看注释)

  const obj = {    name: "小明", age: 18    }//或者const obj = {    }//这里不能使用const,const定义的是常量,无法修改;let demoBute= obj.name;//使用 Object.defineProperty 定义属性名为 name 的属性Object.defineProperty(obj, "name", {//可枚举属性,可以在 for...in 循环中被枚举enumerable: true,//可配置属性,可以使用 delete 运算符删除属性configurable: true,//获取属性值的函数get: function () {console.log("获取,收集依赖");return demoBute},//设置属性值的函数set: function (value) {console.log("更新,通知用户");demoBute = value;}})//修改,触发set函数obj.name = "小红"//控制台输出:更新,通知用户//调用,出发get函数console.log(obj.name);//控制台输出:获取,收集依赖//小明//多次调用,看下运行顺序,按照调用顺序依次执行(set > get > log)//只要调用obj都会触发依赖函数obj.name = "小红";             //set >console.log(obj.name);         //get > log//控制台输出: //更新,通知用户//获取,收集依赖//小红

3、get和set

  •  get 函数的作用是在访问属性值时被调用,它不接受任何参数,但需要返回属性的值。在示例中,我们通过return demoBute返回了name的属性值 。
  • set 函数的作用是在设置属性值时被调用,它接受一个参数 value,该参数表示要设置的属性值。在示例中,我们直接把修改后的值value 赋值给demoBute,实现更新。

4、注意事项

  1. get 和set 函数,不会同时被触发,它们根据属性的读取或设置操作来决定调用哪个函数;
  2. 该方法按照调用顺序,从上到下依次执行,就是有更新就只运行set函数,没更新,就只运行get函数。

二、Proxy

1、Proxy方法是一个允许您拦截并自定义对象的底层操作。通过使用Proxy,您可以拦截对象的各种操作,如属性访问、属性赋值、函数调用等,并在这些操作发生时执行自定义行为;在Proxy中,target 是您要代理的目标对象, handler 是一个包含各种拦截操作的对象。 handler 对象中的每个属性都是一个特殊的拦截器,用于拦截不同的操作。

2、基本语法

const target = {...... }const handler = {get(target, property, receiver){//拦截属性的读取操作},set(target, property, value, receiver){//拦截属性}
}​​​​​​​const proxy = new Proxy(target, handler);

3、在ES6的Proxy中,get和set是两个常用的拦截器函数,用于拦截对象属性的读取和赋值操作。下面详细介绍这两个函数的用法和功能:

(1)、get(target , property , receiver)

- target :目标对象,即被代理的对象。

- property :要访问的属性名。

- receiver:最初被调用的对象,通常是代理对象或继承代理对象的对象。 - 返回值:返回属性的值。

get 函数在访问目标对象的属性时触发,可以用来拦截属性的读取操作。您可以在 get 函数内部添加自定义的逻辑,例如记录日志、验证访问权限等。下面是一个示例:

const target = {name: "Bob",age: 18
};
const handler = {get(target, property, receiver) {console.log(`正在读取属性:${property}`);return target[property];}
};
const proxy = new Proxy(target, handler);
console.log(proxy.name); // 输出:正在读取属性:name,Bob
console.log(proxy.age); // 输出:正在读取属性:age,18

这里我们创建了一个代理对象 proxy ,当访问 proxy 的属性时, get 函数会被触发,并打印相应的日志信息。

(2)、set(target , property , value , receiver) 

- target :目标对象,即被代理的对象。

- property :要设置的属性名。

- value :要设置的属性值。

- receiver:最初被调用的对象,通常是代理对象或继承代理对象的对象。 - 返回值:返回一个布尔值,表示属性是否设置成功。​​​​​​​

set 函数在给目标对象的属性赋值时触发,可以用来拦截属性的赋值操作。您可以在 set 函数内部添加自定义的逻辑,例如验证赋值的合法性、记录日志等。下面是一个示例:

const target = {name: "Carl",age: 20
};
const handler = {set(target, property, value, receiver) {console.log(`正在设置属性:${property},新值为:${value}`);target[property] = value;return true;}
};
const proxy = new Proxy(target, handler);
proxy.age = 30; // 输出:正在设置属性:age,新值为:30
console.log(proxy.age); // 输出:30

在这里,我们给proxy的age属性赋值时,set函数会被触发,并打印相应的日志信息;通过get 和 set 拦截器函数,您可以在读取和赋值属性时执行自定义的行为,从而实现更灵活和可控的对象操作。

(3)、get和set完整实例​​​​​

const target = {name: "Alice",age: 25
};const handler = {get(target, property, receiver) {console.log(`正在读取属性:${property}`);return target[property];},set(target, property, value, receiver) {console.log(`正在设置属性:${property},新值为:${value}`);target[property] = value;return true;}
};const proxy = new Proxy(target, handler);console.log(proxy.name);     // 输出:正在读取属性:name,Alice
proxy.age = 30;             // 输出:正在设置属性:age,新值为:30
console.log(proxy.age);     // 输出:正在读取属性:age,30

4、handler对象中的其它参数

  •  get(target, property, receiver):拦截属性的读取操作。
  •  set(target, property, value, receiver):拦截属性的赋值操作。
  •  apply(target, thisArg, argumentsList):拦截函数的调用操作。
  •  has(target, property):拦截in操作符的操作。
  •  deleteProperty(target, property):拦截属性的删除操作
  •  ......

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

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

相关文章

Net6下Tracer.Serilog.Fody的serilog配置

得益于Net6、Net7下的新结构,不再需要startup.cs文件,configuration也好读取了; 我比较喜欢在appsettings.json中配置serilog,所以在2步配置时,第一步前面就直接从配置文件configuration中读取,并设置Log.…

uniapp快速开发小程序全流程

uniapp快速开发小程序全流程 完整项目代码:https://gitee.com/Zifasdfa/ziyi-app 欢迎fork与star 1 项目效果及环境准备 1.1 项目效果 本文主要使用uniapp实现一个简单的app应用 1.2 环境准备&项目初始化 ①node环境:去node.js官网下载稳定版的nod…

微服务之Eureka服务注册中⼼

关于务注册中⼼服 服务注册中⼼本质上是为了解耦服务提供者和服务消费者,尽可能量使两者联系可控在一定的范围外 1.在父项目下下引入 Spring Cloud 依赖 <dependencyManagement> <dependencies> <!-- SCN --> <dependency> <groupId> org.sp…

【网站 全选和单选】js 实现-点击全选按钮时,所有的按钮都会被选中或取消选中。

要实现的效果如图&#xff1a; 代码实现&#xff1a; <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport…

String常用方法

isEmpty() 判断字符串是否为空。 contains(CharSequence chars) 判断是否包含指定的字符系列。 String toUpperCase() 使用默认语言环境的规则将此 String 中的所有字符都转换为大写。 String toLowerCase() 使用默认语言环境的规则将此 String 中的所有字符都转换为小写。 …

Loki+promtail+Grafana监控docker容器日志

目标&#xff1a;监控docker容器的日志&#xff0c;适用于生产环境 效果&#xff1a; 需要的工具&#xff1a;Loki&#xff0c;promtail&#xff0c;Grafana 通过安装promtail容器收集日志&#xff0c;并把日志发送给loki存储处理&#xff0c;由Grafana展示日志。 参考官网的…

Windows bat隐藏运行窗口的几种方案

文章目录 一、背景二、测试数据三、隐藏bat运行窗口方案1. 使用VBScript脚本2. 使用mshta调用js或vbs脚本3. 将bat编译为exe程序4. 使用任务计划程序 一、背景 有些程序在执行批处理脚本时&#xff0c;可能会看到dos窗口&#xff0c;或者看到窗口一闪而过。如果批处理脚本执行…

(EMQX)STM32L+BC20+MQTT协议传输温湿度,ADC,电压,GPS数据到EMQX

1、材料准备 准备以下材料 2、设备连接 2.1 插入物联网卡&#xff0c;天线 首先把BC20核心板从开发板上拆下来 然后将物联卡放置在BC20核心板内 物联卡放置完成将BC20核心板重新插入到开发板内&#xff08;注意不要弄错方向&#xff09; 同时接入天线 2.2 连接ST-Link仿真…

Python 算法基础篇:大O符号表示法和常见时间复杂度分析

Python 算法基础篇&#xff1a;大 O 符号表示法和常见时间复杂度分析 引言 1. 大 O 符号表示法 a ) 大 O 符号的定义 b ) 示例代码 2. 常见时间复杂度分析总结 引言 在分析和比较算法的性能时&#xff0c;时间复杂度是一项重要的指标。而大 O 符号表示法是用来描述算法时间复杂…

动态规划01背包之416分割等和子集(第10道)

题目&#xff1a; 给你一个 只包含正整数 的 非空 数组 nums 。请你判断是否可以将这个数组分割成两个子集&#xff0c;使得两个子集的元素和相等。 示例&#xff1a; 解法&#xff1a; 先复习一下01背包问题&#xff1a; dp[i][j]的含义&#xff1a;从下标为[0-i]的物品里…

Linux->初识计算机网络

目录 前言&#xff1a; 1 网络发展背景 2 协议 2.1 网络协议初识 2.2 协议分层 2.3 OSI、TCP/IP层状模型 2.4 协议和操作系统的关系 2.5 根据协议栈的通信 3 网络中的地址管理 前言&#xff1a; 本篇当中没有任何关于网络编程的讲解&#xff0c;全部是对网络的宏观理解…

【数学建模】 灰色预测模型

数学建模——预测模型简介 https://www.cnblogs.com/somedayLi/p/9542835.html 灰色预测模型 https://blog.csdn.net/qq_39798423/article/details/89283000?ops_request_misc&request_id&biz_id102&utm_term%E7%81%B0%E8%89%B2%E9%A2%84%E6%B5%8B%E6%A8%…

Mysql数据库备份、索引、视图

目录 备份&#xff1a;先创建如下数据库和表 1、使用mysqldump命令备份数据库中的所有表 2、备份booksDB数据库中的books表 3、使用mysqldump备份booksDB和test数据库 4、使用mysqldump备份服务器中的所有数据库 5、使用mysql命令还原第二题导出的book表 6、进入数据库使…

Jenkins Pipline使用SonarScanner 检查 VUE、js 项目 中遇到的Bug

在 Jenkins 上使用 Pipline 进行集成&#xff0c;利用 SonarScanner 做静态代码扫描的过程中&#xff0c;遇到了几个问题&#xff0c;这里记录了一点解决办法。 在Jenkins上使用Pipline进行集成&#xff0c;利用SonarScanner做静态代码扫描的过程中&#xff0c;遇到了几个问题&…

MySQL 进阶之王,MySql 性能实战源码 + 笔记 + 项目实战

随着互联网时代的兴起&#xff0c;MySQL 在数据库领域日益显现出举足轻重的地位&#xff0c;它不断扩大的用户群体就是很好的证明。在这样的背景下&#xff0c;需要越来越多的人在知识资源方面为之付出&#xff0c;将自己对 MySQL 数据库的学习过程、运维经验、个人理解等记录下…

scripy其他

持久化 # 爬回来&#xff0c;解析完了&#xff0c;想存储&#xff0c;有两种方案 ## 方案一&#xff1a;一般不用 parse必须有return值&#xff0c;必须是列表套字典形式--->使用命令&#xff0c;可以保存到json格式中&#xff0c;csv中scrapy crawl cnblogs -o cnbogs.j…

生活的意义

当前在工作中&#xff0c;但是有30分钟的等待时间&#xff0c;不知道要说点什么&#xff0c;突然想到了&#xff1a;人生的意义&#xff01;本人的一个小小的思考。由于话题太过敏感 标题就写了 "生活的意义" 每天上班日复一日&#xff0c;没有爱好。生活中除了日常…

Web3 开发指南:使用 NFTScan NFT API 构建一个 NFT 链上追踪器

对于大多数 Web3 团队来说&#xff0c;构建一个完整的链上 NFT 数据追踪系统是一项具有挑战性的任务&#xff0c;构建一个 NFT 链上追踪器更是如此。涉及到处理区块链上的智能合约和交易数据&#xff0c;并将其与外部数据源进行整合和分析工作量是十分巨大的&#xff1a; 区块链…

http请求状态码汇总

目录 常见的状态码 所有状态码汇总 1xx——临时响应信息提示&#xff1b;这些状态代码表示临时的响应。客户端在收到常规响应之前&#xff0c;应准备接收一个或多个1xx 2xx——成功 3xx——重定向&#xff1a;表示要完成请求&#xff0c;需要进一步操作。通常&#xff0c;…