Proxy的使用方法和13种拦截操作

news2025/2/27 20:50:06

前言

proxy是ES6新推出的方法,功能很强大。属于元编程,也就是修改js本身的一些东西。可以对数组,对象,函数等引用类型的对象进行一些复杂的操作。

其中,大部分人应该最熟悉的莫过于vue3中使用proxy替换了defineProperty,而且还实现了本身defineProperty不能实现的一些东西。

proxy通过拦截一个对象的属性,使这个对象被操作的时候,我们可以执行一些自定义的逻辑。

proxy一共有13种拦截操作

拦截属性

get(拦截对象属性的读取)

当对象一个对象的某个值被读取时,可以通过重写get方法,在get函数中执行自定义的逻辑,通过return返回自定义的结果

        let data = {
            name:'wjt',
            age:29
        }
        let _data = new Proxy(data,{
            get:(target,propKey,receiver)=>{
              console.log(target,propKey,receiver,'函数参数')
              if(target[propKey]){  /*Proxy参数1data对象中也存在该属性*/
                return target[propKey]
              }else{
                /*data对象中不存在该属性时*/
                return undefined
              }
            }
        })
        console.log(_data.name,'访问name属性')
        console.log(_data.age,'访问age属性')
        console.log(_data.game,'访问不存在的属性game')

 set(拦截对象属性的设置)

当修改对象属性时,可以使用set方法进行拦截,并且可以实现两个对象数据的同步

<body>
    <button onclick="getName()">查看name属性</button>
    <button onclick="getAge()">查看age属性</button>
    <button onclick="addAge()">增加age</button>
    <script>
        let data = {
            name:'wjt',
            age:29
        }
        let _data = new Proxy(data,{
            //get方法
            get:(target,propKey,receiver)=>{
              if(target[propKey]){  
                return target[propKey]
              }else{
                return undefined
              }
            },

            //set方法
            set:(target,keyName,value)=>{
                console.log(target,keyName,value,'修改_data的属性')
                //...可以进行修改值的拦截操作
                target[keyName] = value
            }
        })

         
        let getName = ()=>{
            console.log(_data.name,'_data.name')
        }
        let getAge = ()=>{
            console.log(_data.age,'_data.age')
        }
        let addAge = ()=>{
            _data.age++
            console.log(data,'data的值')
            console.log(_data,'_data的值')
        }
        </script>
</body>

 apply(拦截Proxy实例作为函数函数调用)

 

        let fn = function(){
            console.log('我是原始函数')
        }
        let _fn = new Proxy(fn,{
            apply:function(target,ctx,args){
              console.log(this,'this的值')
              console.log(target,'target的值')
              console.log(ctx,'ctx的值')
              console.log(args,'arguments参数')
              return `我是代理的_fn函数,我还传递了参数值1为${args[0][0]},参数值2是${args[0][1]}`
            }
        })
        console.log(_fn(['wjt',29])) 

 

has(拦截对象的属性是否会被in应算符发现)

        let data = {
            name:'wjt',
            age:29,
            hideProp:'我是隐藏的属性,不想被in运算符访问到'
        }
        let _data = new Proxy(data,{
            has:(target,key)=>{
                if(target[key] && key === 'hideProp'){
                    return false
                }else{
                    return key in target
                }
            }
        })
        console.log('name' in _data,_data['name'],'查看name属性')
        console.log('age' in _data,_data['age'],'查看age属性')
        console.log('hideProp' in _data,_data['hideProp'],'查看hideProp属性')

 

construct(拦截Proxy实例作为构造函数)

用于拦截new命令,可以进行将一个函数进行代理,生成一个新的构造函数

        let Fn = function(){
            console.log('必须是函数')
        }
        let _Fn = new Proxy(Fn,{
            age:29,
            construct:function(target,args){
                console.log(target,'target的值')
                console.log(args,'参数')
                return {
                    name:args[0].name,
                    age:this.age  /*这里的this就是[[new Proxy(Fn,handler)]]中的handler,this.age也就是上面定义的age*/
                }
            }
        })
       console.log(new _Fn({name:'wjt'}),'使用_Fn构造的实例对象') 

deleteProperty(拦截删除属性操作)

在使用delete删除对象的属性是,可以使用deleteProperty方法去自定义是否可以删除。返回true,就是可以被删除;如果throw一个错误或者返回false,就不可以删除

        let data = {
            canDeleteProp:'可以被删除的属性',
            notDeleteProp:'不想被删除的属性'
        }
        let _data = new Proxy(data,{
            deleteProperty:(target,key)=>{
               if(key === 'notDeleteProp'){
                // throw new Error('不可以被删除')
                return false
               }else{
                delete target[key]
                return true
               }
            }
        })
        delete _data.canDeleteProp
        console.log(_data,data,'删除了canDeleteProp属性')
        delete _data.notDeleteProp
        console.log(_data,data,'notDeleteProp属性无法被删除')

 defineProperty(拦截是否可以定义原来不存在的属性)

如果返回false,就可以让新的对象无法定义不存在的属性

        let data = {
            name:'wjt',
            age:29
        }
        let _data = new Proxy(data,{
            defineProperty:(target,key,descriptor)=>{
                return false
            }
        })
        _data.newProp1 = '_datanewProp'
        data.newProp2 = 'datanewProp'
        console.log(_data,'_data')
        console.log(data,'data')

getOwnPropertyDescriptor(返回描述对象或者undefined)

可以自定义让某个属性访问时是否返回描述对象

        let data = {
            name:'wjt',
            age:29,
            desProp:'属性信息'
        }
        let _data = new Proxy(data,{
          getOwnPropertyDescriptor:(target,key)=>{
            if(key === 'desProp'){
             return Object.getOwnPropertyDescriptor(target,key)
            }else{
                return 
            }
          }
        })

       console.log(Object.getOwnPropertyDescriptor(_data,'name')) 
       console.log(Object.getOwnPropertyDescriptor(_data,'age'))
       console.log(Object.getOwnPropertyDescriptor(_data,'desProp'))

getPrototypeOf(获取对象原型)

使用getPrototypeOf可以拦截设置该对象的原型对象

        let data = {
            name:'wjt',
            age:29
        }
        let obj = {
            prop:'被作为原型对象'
        }
        
        let _data = new Proxy(data,{
          getPrototypeOf(target){
            return obj
          }
        })
        console.log(Object.getPrototypeOf(data),'data的原型对象是默认的原型对象')
        console.log(Object.getPrototypeOf(_data),'_data的原型对象是使用obj')

isExtensible(拦截isExtensible)

Object.isExtensible属性,决定对象是否可扩展

        let data = {
            name:'wjt',
            age:29
        }
        let _data1 = new Proxy(data,{
            isExtensible:(target)=>{
                return true
            }
        })
        let _data2 = new Proxy(data,{
            isExtensible:(target)=>{
                return false
            }
        })
        console.log(Object.isExtensible(_data1),'_data1')
        console.log(Object.isExtensible(_data2),'_data2')

 

 

ownKeys(拦截迭代属性的时候可访问的属性)

返回一个数组,内部的值都是可以跌迭代访问的

可控制以下几种迭代

  • Object.getOwnPropertyNames()
  • Object.getOwnPropertySymbols()
  • Object.keys()
  • for...in循环

这里以keys作示例

        let data = {
            name:'wjt',
            age:29,
            prop:'newProp'
        }

        let _data = new Proxy(data,{
            ownKeys:(target)=>{
              return ['name','age']
            }
        })
        for(let key of Object.keys(_data)){
            console.log(key,':',_data[key])
        }

 preventExtensions(拦截Object.preventExtensions方法)

Object.preventExtensions是可以设置禁止对象被扩展

let data = {
    name:'wjt',
    age:29
}

let _data = new Proxy(data,{
    preventExtensions:(target)=>{
        return false
    }
})

_data.prop = 'newProp'
console.log(Object.preventExtensions(data),'data')
console.log(Object.preventExtensions(_data),'_data')

 

setPrototypeOf(拦截setPrototypeOf方法)

可以拦截限制是否可以修改原型对象

        let data = {
            name:'wjt',
            age:29
        }
        let obj = {
            name:'可以作为原型对象'
        }
        let _data = new Proxy(data,{
            setPrototypeOf:(target,proto)=>{
               return false
            }
        })
        
        console.log(Object.setPrototypeOf(data,obj),'data')
        console.log(Object.setPrototypeOf(_data,obj),'_data')

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

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

相关文章

Vue-API

$parent 和 $children $parent 父传子--在子组件中使用&#xff0c;放在计算属性、生命周期中&#xff1a; $children 子传父--方法中使用&#xff1a; $nextTick: $ref: 操作dom $set、$delete:

UML-实现图(组件图和部署图)

实现图是从系统的层次来描述的&#xff0c;描述硬件的组成和布局&#xff0c;描述软件系统划分和功能实现。 UML-实现图&#xff08;组件图和部署图&#xff09; 一、组件图1.组件图的元素&#xff08;1&#xff09;组件&#xff08;2&#xff09;接口&#xff08;3&#xff09…

linux系统nginx工具的一些应用和基于nginx做虚拟主机

nginx高级应用 虚拟目录监控模块配置文件创建用户名密码客户端访问 限制传输速度&#xff08;服务层&#xff09; nginx虚拟主机基于ip基于域名基于端口 nginx配置文件中的每个语句要以 ; 结尾 虚拟目录 配置文件中的server块中编辑&#xff1a;location /test {alias /usr/…

SparkSQL初体验

SparkSQL初体验 命令式的 API RDD 版本的 WordCount val conf new SparkConf().setAppName("ip_ana").setMaster("local[6]") val sc new SparkContext(conf)sc.textFile("hdfs://master:9000/dataset/wordcount.txt").flatMap(_.split("…

Visual Studio 2019 ctrl+f 呼出查找和替换窗口

有时候 ctrlshiftf 呼出查找和替换窗口不起作用&#xff0c;可能和其它程序的快捷键冲突&#xff0c;解决方案&#xff1a; ------------英文版本------------ 依次点击VS菜单栏中的 Tools - Options - Environment - Keyboard: 1. 在右侧的 Show commands containing: 文本框输…

单列的堆叠柱状图

目的 MSingleColumnStackBarChart类被设计用于创建只有单列的堆叠柱状图&#xff0c;用于血糖数据的统计。以下是封装这个类的目的的详细描述&#xff1a; 抽象复杂性&#xff1a; 通过创建MSingleColumnStackBarChart类&#xff0c;你将复杂的MPAndroidChart库的使用和配置封…

创意交融:集成自定义报表和仪表盘设计器,实现图标替换

前言 在现代数据分析领域&#xff0c;随着对报表和数据分析的需求不断增长&#xff0c;市场上涌现了许多嵌入式报表工具。这些工具能够与企业现有的OA、ERP、MES、CRM等应用系统深度集成&#xff0c;实现对业务数据的自助式分析。然而&#xff0c;在实际应用中&#xff0c;不同…

【量化交易实战记】小明的破晓时刻——2023下半年新能源汽车板块的成功掘金之旅

在2023年的炎炎夏日&#xff0c;小明在不断的观察分析市场的过程中&#xff0c;突然敏锐地察觉到了新能源汽车市场的风云变幻。他日复一日地研读行业报告、追踪政策动向、分析公司财报&#xff0c;以及密切关注全球市场动态。那段时间里&#xff0c;新能源汽车行业仿佛迎来了一…

Vue中父子组件通信

聚沙成塔每天进步一点点 本文内容 ⭐ 专栏简介Vue中父子组件通信1. Props父组件&#xff1a;子组件&#xff1a; 2. 自定义事件子组件&#xff1a;父组件&#xff1a; 3. 使用 v-model子组件&#xff1a;父组件&#xff1a; 4. 使用$refs子组件&#xff1a;父组件&#xff1a; …

必示科技助力中国联通智网创新中心通过智能化运维(AIOps)通用能力成熟度3级评估

2023年12月15日&#xff0c;中国信息通信研究院隆重公布了智能化运维AIOps系列标准最新批次评估结果。 必示科技与中国联通智网创新中心合作的“智能IT故障监控定位分析能力建设项目”通过了中国信息通信研究院开展的《智能化运维能力成熟度系列标准 第1部分&#xff1a;通用能…

通用外设-2.8‘TFT屏的使用

前言 一、验证连接是否正确 二、更改自己想用的图像 1.取模软件 Image2Lcd 2.9 的使用 2.使用 总结 前言 本文在中景园的代码上改写而来&#xff0c;主要记录下使用记录 一、验证连接是否正确 1.按内容说明进行线路连接 2.运行程序&#xff0c;因为内部有图片样本&…

这可能是最全面的Java并发编程八股文了

内容摘自我的学习网站&#xff1a;topjavaer.cn 分享50道Java并发高频面试题。 线程池 线程池&#xff1a;一个管理线程的池子。 为什么平时都是使用线程池创建线程&#xff0c;直接new一个线程不好吗&#xff1f; 嗯&#xff0c;手动创建线程有两个缺点 不受控风险频繁创…

23年全球数字经济发展如何?这本《白皮书》告诉你答案丨附下载

这一年&#xff0c;全球主要国家优化数字经济政策布局&#xff0c; 促进数字产业化创新升级、发展数字基础设施&#xff1b; 这一年&#xff0c;全域国际合作让“命运共同体” 构建见成效&#xff0c; 全球经济多极化趋势加强&#xff0c;中国坐拥Top1数字市场&#xff1b; …

第二证券:抢占技术前沿 中国光伏企业结伴“走出去”

2024年新年前后&#xff0c;光伏职业分外忙碌。据证券时报记者不完全统计&#xff0c;晶澳科技、华晟新动力、高测股份、华民股份等多家企业宣告新建项目投产&#xff0c;安徽皇氏绿能等企业的项目也迎来设备安装的重要节点。 证券时报记者采访多家企业的负责人后了解到&#…

js日期排序(使用sort)

根据日期进行排序&#xff0c;也可以根据number类型的大小来进行排序 按日期排序的函数 let data [{id: 2,time: 2019-04-26 10:53:19},{id: 4,time: 2019-04-26 10:51:19}, {id: 1,time: 2019-04-26 11:04:32}, {id: 3,time: 2019-04-26 11:05:32} ] //property是你需要排序…

一款好用的开源思维导图软件 docker部署教程

目录 Simple mind map简介 Simple mind map特点 1.拉取镜像 2.创建并启动容器 方式1&#xff1a;docker启动 方式2&#xff1a;docker compose启动 3.使用 4.源码地址 Simple mind map简介 .一个 Web 思维导图&#xff0c;基于思维导图库、Vue2.x、ElementUI 开发&#…

前端框架前置课Node.js学习(1) fs,path,模块化,CommonJS标准,ECMAScript标准,包

目录 什么是Node.js 定义 作用: 什么是前端工程化 Node.js为何能执行Js fs模块-读写文件 模块 语法: 1.加载fs模块对象 2.写入文件内容 3.读取文件内容 Path模块-路径处理 为什么要使用path模块 语法 URL中的端口号 http模块-创建Web服务 需求 步骤: 案例:浏…

geemap学习笔记048:光谱变换

前言 Earth Engine中有多种光谱变换方法。其中包括图像上的实例方法&#xff0c;例如 normalizedDifference()、unmix()、rgbToHsv() 和 hsvToRgb()。 1 导入库并初始化 import ee import geemapee.Initialize()2 全色图像锐化(Pan sharpening) Map geemap.Map(center[40,…

Java 使用 EasyExcel 爬取数据

一、爬取数据的基本思路 分析要爬取数据的来源 1. 查找数据来源&#xff1a;浏览器按 F12 或右键单击“检查”打开开发者工具查看数据获取时的请求地址 2. 查看接口信息&#xff1a;复制请求地址直接到浏览器地址栏输入看能不能取到数据 3. 推荐安装插件&#xff1a;FeHelper&a…

个人网站制作 Part 6 添加高级特性(页面动画、服务端集成) | Web开发项目

文章目录 &#x1f469;‍&#x1f4bb; 基础Web开发练手项目系列&#xff1a;个人网站制作&#x1f680; 添加页面动画&#x1f528;使用CSS动画&#x1f527;步骤 1: 添加动画效果 &#x1f528;使用JavaScript实现动画&#x1f527;步骤 2: 使用JavaScript添加动画 &#x1…