前端知识学习之proxy代理对象

前端proxy代理对象

1.学习背景

学习vue3过程中,发现vue3相比于vue2的最大优势在于,尤雨溪大佬在vue3中使用proxy 代理对象,vue2中使用的双向绑定Object.defineProperty,这两者有什么区别

2.Object.defineProperty

使用方法:

// obj:绑定属性的目标对象
// property: 绑定的属性名
// descriptor: 属性描述(配置),且此参数本身为一个对象
Object.defineProperty(obj, property, descriptor)
  • obj:绑定属性的目标对象
  • property: 绑定的属性名
  • descriptor: 属性描述(配置),且此参数本身为一个对象
    • value: 设置属性默认值
    • writable:设置属性是否能够修改
    • enumerable: 设置属性是否可以枚举,即是否允许遍历
    • configurable: 设置属性是否可以删除或编辑
    • get: 获取属性的值
    • set: 设置属性的值

示例:

//将对象obj 中的值传给target
let obj = {age: 18,arr: [1, 2, 3]
}
let target = {}for (let key in obj) {Object.defineProperty(target, key, {value: obj[key]})
}
console.log(target) // 这样我们就获得了obj中的值》》》》》》》》》》》》》》》》》》》》》》》》
{age: 18, arr: [1, 2, 3]}
2.1 通过writable设置是否可写/修改

使用writable参数判断对象的值是否能修改

let param = {};
Object.defineProperty(param,'nums',{value:18,writable:false});
console.log(param);
param.nums=20;
console.log(param);
》》》》》》》》》》》》》》》》》》》》》》》》
{nums: 18}
{nums: 18}
2.2 通过enumerable设置是否允许遍历
let param = {};
Object.defineProperty(param,'nums',{value:18,enumerable:false});
Object.defineProperty(param,'name',{value:999,enumerable:true});
for(let key in param){console.log(key)
}
》》》》》》》》》》》》》》》》》》》》》》》》
name //只打印name
2.3 通过configurable设置属性是否可删
let param = {};
Object.defineProperty(param,'nums',{value:18,configurable:false});
Object.defineProperty(param,'name',{value:999,configurable:true});
delete param.nums
delete param.name
console.log(param)
》》》》》》》》》》》》》》》》》》》》》》》》
{nums: 18} //name 被删掉了
2.4 通过get、set设置值

注意:在使用get和set方法时不能使用value和writable属性

getlet param = {};
Object.defineProperty(param,'nums',{get(){return 20}});
console.log(param.nums)
》》》》》》》》》》》》》》》》》》》》》》》》
20 //输出setlet param = {};
Object.defineProperty(param,'nums',{set(val){console.log(val)}});
param.nums=10
》》》》》》》》》》》》》》》》》》》》》》》
10 //输出

3.Proxy代理对象

// Proxy的基础用法如下,它需要传入两个参数
const p = new Proxy(target, handler)target:要使用 Proxy 包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)。
handler: 一个通常以函数作为属性的对象,各属性中的函数分别定义了在执行各种操作时代理 p 的行为。
3.1定义一个代理对象
const obj = {age: 18
}
const objProxy = new Proxy(obj, {})
console.log(objProxy) // 我们这里打印代理对象
3.2 Proxy捕获器

在定义代理的过程中,handler 被称之为捕获器

下面为三个捕获器:

  • get捕获器
  • set捕获器
  • defineProperty捕获器
get捕获器:
const obj = {age: 18
}
const objProxy = new Proxy(obj, {get(target, key) {console.log('获取对象' + key + '属性的值') // 这里我们可以捕捉到获取对象key的值到操作return target[key]}
})
console.log(obj.age) // 这里先输出 获取对象age属性的值,   再输出 18

get方法用于拦截对象的读取属性操作,它有三个参数,并且可以返回任何值

  • target:目标对象
  • property: 被读取的属性名
  • receiver: Proxy 或者继承 Proxy 的对象

get方法可以拦截目标对象的以下操作

  • 访问属性:如obj.age
  • 访问原型链上的属性:Object.create(obj)[age]
  • 访问一个内置对象的属性:Reflect.get(arget, propertyKey[, receiver])
set捕获器:
const obj = {age: 18
}
const objProxy = new Proxy(obj, {set(target, key, val) {if(key === 'name' && typeof val === 'string') { // 可以做属性类型检查拦截等操作target[key] = val} else {throw new TypeError("该属性的值必须是String类型");}}
})
console.log(obj.age)
set方法是设置属性值操作的捕获器。它有四个参数,this会绑定到handler对象上,并且返回一个布尔值
  • target: 目标对象
  • property:将被设置的属性名或一个Symbol
  • value:新属性值
  • receiver: 最初被调用的对象。通常是 proxy 本身,但 handler 的 set 方法也有可能在原型链上,或以其他方式被间接地调用(因此不一定是 proxy 本身)。

注意:假设有一段代码执行 obj.name = "mr.z"obj 不是一个 proxy,且自身不含 name 属性,但是它的原型链上有一个 proxy,那么,那个 proxy 的 set() 处理器会被调用,而此时,obj 会作为 receiver 参数传进来。

set方法会拦截目标对象的以下操作:

  • 给属性赋值:objProxy.name = ‘mr.z’
  • 给继承到属性赋值:Object.create(objProxy)[name] = ‘mr.z’
  • Reflect.set() // 这个不做过多讲解

对于以下情况,Proxy会抛出错误

  • 若目标属性是一个不可写及不可配置的数据属性,则不能改变它的值。
  • 如果目标属性没有配置存储方法,即 [[Set]] 属性的是 undefined,则不能设置它的值。
  • 在严格模式下,如果 set() 方法返回 false,那么也会抛出一个 TypeError异常。
defineProperty 捕获器
let obj = new Proxy({}, {defineProperty(target, property, descriptor) {console.log('设置的属性: ' + prop);return true;}
});var desc = { configurable: true, enumerable: true, value: 'mr.z' };
Object.defineProperty(obj, 'name', desc); // "设置的属性: name"

defineProperty方法有三个参数,并且它的返回值必须是一个布尔值

  • target:目标对象
  • property:待检索其描述的属性名
  • descriptor:待定义或修改的属性的描述符

Proxy中共有13个捕获器,它们用于我们对对象、函数的方法调用监听。下面是Proxy捕获器以及它们的触发条件。

对象中的方法对应触发条件
handler.getPrototypeOf()Object.getPrototypeOf 方法的捕捉器
handler.setPrototypeOf()Object.setPrototypeOf 方法的捕捉器
handler.isExtensible()Object.isExtensible 方法的捕捉器
handler.preventExtensions()Object.preventExtensions 方法的捕捉器
handler.getOwnPropertyDescriptor()Object.getOwnPropertyDescriptor 方法的捕捉器。
handler.defineProperty()Object.defineProperty 方法的捕捉器
handler.has()in 操作符的捕捉器
handler.get()属性读取操作的捕捉器
handler.set()属性设置操作的捕捉器
handler.deleteProperty()delete 操作符的捕捉器
handler.ownKeys()Object.getOwnPropertyNames 方法和 Object.getOwnPropertySymbols 方法的捕捉器
handler.apply()函数被apply调用操作的捕捉器
handler.construct()new 操作符的捕捉器

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

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

相关文章

ECMAScript语法

什么是ECMAScript ECMAScript 是一种由 ECMA国际(前身为欧洲计算机制造商协会)通过 ECMA-262 标准化的脚本程序设计语言。 ECMAScript 是一种可以在宿主环境中执行计算并能操作可计算对象的基于对象的程序设计语言。ECMAScript 最先被设计成一种 Web 脚…

java使用mapper操作mysql

上半部分搭建springboot 简单使用数据库查询 添加链接描述 在impl接口实现操作 如 package com.service.impl; import com.dao.UserMapper; import com.pojo.User; import com.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import…

基于SSM SpringBoot vue个人博客网站

基于SSM SpringBoot vue个人博客网站 系统功能 首页 图片轮播 博客文章 搜索 登录注册 论坛 留言板 个人中心 我的收藏 后台管理 登录 个人中心 博客分类管理 博客文章管理 论坛管理 系统管理 管理员管理 注册用户管理 开发环境和技术 开发语言:Java 使用框架:…

实战经验分享:如何优化即时通讯应用的性能?

在当今移动互联网时代,即时通讯应用如雨后春笋般涌现,用户对即时通讯应用的性能和体验要求也越来越高。作为即时通讯开发领域的专家,我将分享一些优化即时通讯应用性能的实战经验,帮助开发者提升应用质量和用户满意度。 1. 优化网…

【Leetcode每日一刷】贪心算法| 45.跳跃游戏 II

1、45.跳跃游戏 II 🦄解题思路: 这题还是比【55.跳跃游戏】难一些的。第一个版本只是说,求跳跃的范围,覆盖到了终点即可。这题则是,能保证覆盖范围到达终点,求的是最少跳几次,跳到终点。 这题…

289页初中级前端题助你拿下Offer,终局之战

HTML、CSS、JS三大部分都起什么作用? HTML内容层,它的作用是表示一个HTML标签在页面里是个什么角色;CSS样式层,它的作用是表示一块内容以什么样的样式(字体、大小、颜色、宽高等)显示;JS行为层…

Redis缓存【重点】

参考链接 https://xiaolincoding.com/redis/cluster/cache_problem.html#%E7%BC%93%E5%AD%98%E9%9B%AA%E5%B4%A9 目录 缓存雪崩大量数据同时过期Redis 故障宕机 缓存击穿第一种方案,非法请求的限制第二种方案,缓存空值或者默认值第三种方案,使…

01、MongoDB -- 下载、安装、配置文件等配置 及 副本集配置

目录 MongoDB -- 下载、安装、配置 及 副本集配置启动命令启动 mongodb 的服务器(单机和副本集)启动单机模式的 mongodb 服务器启动副本集的 3 个副本节点(mongodb 服务器) 启动 mongodb 的客户端 MongoDB 下载MongoDB 安装1、解压…

App自动化测试笔记(一):搭建环境

一、三个环境 1、android模拟器:模拟安卓手机 2、androidSDK:android SDK给你提供开发测试所必须android API类库 3、java:android底层是c、c语言,应用层是java语言 二、java环境搭建 java安装 安装jdk-8u151-windows-x64.exe 配置环境变量…

JAVA的学习日记DAY1

JAVA的学习日记(2024.3.1)(b站韩顺平老师课程学习笔记版) ps:捡起忘光光的Java语言 Sublime //1. public是公有,class是类 //2. public class Hello表示Hello是一个类,是一个public公有的类 //3. Hello{…

MySQL-索引:聚集索引、覆盖索引、组合索引、前缀索引、唯一索引(附带例子解释)

MySQL-索引:聚集索引、覆盖索引、组合索引、前缀索引、唯一索引(附带例子解释) 1、聚集索引2、覆盖索引3、组合索引4、前缀索引5、唯一索引6、再深入理解覆盖索引7、拓展 1、聚集索引 在数据库中,聚集索引决定了表数据行的物理存…

Linux:修改文件权限

简介 在Linux系统中,权限管理是文件和目录安全性的核心。文件权限是非常重要的,它们决定了哪些用户可以读取、写入或执行文件。 文件权限 用户类别 每个文件和目录都与三种类型的权限相关联,分别针对三个不同的用户类别: 所有…

【Redis | 第二篇】Redis的五种数据类型和相关命令

文章目录 2.Redis的数据类型和相关命令2.1常用数据类型2.2特性和用途2.2.1字符串(String)2.2.2哈希(Hash)2.2.3列表(List)2.2.4集合(Set)2.2.5有序集合(Sorted Set&#…

将组件直接绑定到vue实例上面的写法

怎么将组件直接绑定到vue实例上面? 在实际开发过程中,有多种使用vue组件的方式,有在组件中引入,直接挂载到vue进行全局使用,也有直接挂载到vue实例上面当成vue的一个属性来使用的。下面通过代码来实现将组件直接绑定到…

SwiftUI中stroke属性的使用

在 SwiftUI 中,可以使用 stroke 属性来绘制形状的轮廓线。stroke 属性接受一个 Color 类型的参数,指定轮廓线的颜色。 以下是一个示例代码,演示如何在 SwiftUI 中使用 stroke 属性绘制矩形的轮廓线: import SwiftUIstruct Conte…

linux小记(1)

基本概念:不依靠扩展名来区分文件类型 好处:除了文本文件其他所有windows文件都无法在Linux下运行,包括病毒木马。 坏处:所有的软件都需要对linux单独开发 习惯用后缀来区分文件,方便管理。 -压缩包:*.…

第十五届蓝桥杯软件赛模拟赛第三期(c++,python,java通用)

注:1.填空题用最简单的方式(暴力递归或枚举)得出答案即可。 2.编程题若无思路可用暴力递归或枚举也能拿到不少的分数。 第一题 【问题描述】 请问 2023 有多少个约数?即有多少个正整数,使得 2023 是这个正整数的整数倍…

【ESP32 IDF】UART串口

文章目录 前言一、数据传输的基本概念1.1 串行与并行通信1.2 单工/半双工/全双工通信1.3 同步/异步通信1.4 波特率1.5 UART 四要素 二、串口的使用2.1 配置UART串口2.2 配置UART引脚2.3 安装串口驱动2.4 获取环形缓冲区的数据长度2.5 读取数据2.6 发送数据 总结 前言 UART&…

第十二篇:学习python数据清洗

文章目录 一、啥是数据清洗二、将表格数据导入pandas中1. 准备工作2. 引入csv文件2.1 引入pandas库2.2 读取文件/修改名称3.2 快速浏览数据2.4 修改名字2.5 查找缺失值2.6 删除缺失值 3. 引入Excel文件3.1 引入pandas库3.2 读取Excel文件的人均GDP数据3.3 查看数据类型和non-nu…

Android中的几种定位方式调用详解

目前,移动端大致通过三种方式来进行设备定位:GPS、基站、wifi。本文就详细的讲解一下这几种定位方式和实现方法。 前言 android中我们一般使用LocationManager来获取位置信息,这里面有四中provider: public static final Strin…