【JavaScript】ES6新特性(4)

news2024/11/27 10:26:51

14. Proxy 代理

Proxy 可以对目标对象的读取、函数调用等操作进行拦截,然后进行操作处理
它不直接操作对象,而是像代理模式,通过对象的代理对象进行操作,在进行这些操作时,可以添加一些需要的额外操作

14.1 Object.defineProperty

响应式小功能

<!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>
    <div class="box"></div>
    <script>
        let obj = {}

        // 可以获得一个对象什么时候被设置,什么时候被修改
        // 通过 Object.defineProperty 对对象的某个属性(如data)进行get、set拦截
        // 只要访问这个属性就会调用 get 方法,修改就会调用 set 方法
        Object.defineProperty(obj, "data", {
            get() {
                console.log("get");
            },
            set() {
                console.log("set");
            }
        })

        console.log(obj);

        // 响应修改的内容到 div 标签
        let box = document.querySelector(".box");
        let obj1 = {}
        Object.defineProperty(obj1, "age", {
            get() {
                console.log("get");
                return box.innerHTML;
            },
            set(value) {
                console.log("set", value);
                // 设置dom
                box.innerHTML = value;
            }
        })
    </script>
</body>

</html>

在这里插入图片描述

14.2 Proxy 的 get、set 方法

  • Object.defineProperty 的缺点
    • 每次只能拦截一个属性,需要 for 循环
    • 只能对对象拦截,其他不行

在这里插入图片描述

Proxy 如其名, 它的作用是在对象和和对象的属性值之间设置一个代理,获取该对象的值或者设置该对象的值, 以及实例化等等多种操作, 都会被拦截住, 经过这一层我们可以统一处理,我们可以认为它就是“代理器”

<!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>Proxy</title>
</head>

<body>
    <div class="box"></div>
    <script>
        let box = document.querySelector(".box");

        let obj = {}
        let proxy = new Proxy(obj, {

            get(target, key) {
                console.log("get", target, key);
                // get() 需要一个返回值
                return target[key];
            },

            // target 对应 obj 对象
            set(target, key, value) {
                console.log("set", target, key, value);

                // dom操作
                if (key == "data") {
                    box.innerHTML = value;
                }

                target[key] = value;
            }
        })
    </script>
</body>

</html>

在这里插入图片描述

14.3 has 方法

用于拦截 HasProperty 操作,即在判断 target 对象是否存在 propKey 属性时,会被这个方法拦截
此方法不判断一个属性是对象自身的属性,还是继承的属性

<!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>Proxy的has方法</title>
</head>

<body>
    <div class="box"></div>
    <script>
        let box = document.querySelector(".box");

        let target = {
            _prop: "内部数据"
        }
        let proxy = new Proxy(target, {
            get(target, prop) {
                return target[prop]
            },
            set(target, prop, value) {
                if (prop === "data") {
                    box.innerHTML = value
                }
                target[prop] = value;
            },

            // 设置满足存在条件的属性名,
            // 再进行判断,就判断是否有该属性
            has(target, key) {
                if (key[0] === '_') {
                    return false;
                }
                return key in target;
            }
        })
    </script>
</body>

</html>

在这里插入图片描述

14.4 Proxy拦截不同数据结构

错误1:get方法没有做对方法的处理

使用proxy.size时可以打印get,证明拦截成功,但是使用 proxy.add 方法就报错

报错原因:get方法没有做对方法的处理

<!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>Proxy拦截不同数据结构</title>
</head>

<body>
    <script>
        let s = new Set();

        let proxy = new Proxy(s, {
            get() {
                console.log("get");
            },
            set() {
                console.log("set");
            }
        })
        // 使用proxy.size时可以打印get,证明拦截成功
        // 但是使用 proxy.add 方法就报错
        // 报错原因:get方法没有做对方法的处理
    </script>
</body>

</html>

在这里插入图片描述

错误2:错误原因: this绑定指向错误

正常调用size,add都没问题,但是在使用add方法时添加元素就报错

报错原因: this绑定指向错误,this时指向Proxy代理,但是需要用this指向set结构的属性方法

<!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>Proxy拦截不同数据结构</title>
</head>

<body>
    <script>
        let s = new Set();

        // let proxy = new Proxy(s, {
        //     get() {
        //         console.log("get");
        //     },
        //     set() {
        //         console.log("set");
        //     }
        // })
        // 使用proxy.size时可以打印get,证明拦截成功
        // 但是使用 proxy.add 方法就报错
        // 报错原因:get方法没有做对方法的处理

        // 解决 get 方法没有做对方法的处理
        let proxy = new Proxy(s, {
            get(target, key) {
                // console.log("get");
                return target[key];
            },
            set() {
                console.log("set");
            }
        })
        // 正常调用size,add都没问题,
        // 但是在使用add方法时添加元素就报错
        // 报错原因: this绑定指向错误,this时指向Proxy代理,
        // 但是需要用this指向set结构的属性方法
    </script>
</body>

</html>

在这里插入图片描述

解决 this 绑定指向错误

遇到 Function 都手动绑定一下 this,使用 bind 绑定

<!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>Proxy拦截不同数据结构</title>
</head>

<body>
    <script>
        let s = new Set();

        // let proxy = new Proxy(s, {
        //     get() {
        //         console.log("get");
        //     },
        //     set() {
        //         console.log("set");
        //     }
        // })
        // 使用 proxy.size 时可以打印 get,证明拦截成功
        // 但是使用 proxy.add 放方法就报错
        // 报错原因:get 方法没有做对方法的处理

        // 解决 get 方法没有做对方法的处理
        // let proxy = new Proxy(s, {
        //     get(target, key) {
        //         // console.log("get");
        //         return target[key];
        //     },
        //     set() {
        //         console.log("set");
        //     }
        // })
        // 正常调用 size,add 都没问题,
        // 但是在使用 add 方法时添加元素就报错
        // 报错原因: this 绑定指向错误,this 时指向 Proxy 代理,
        // 但是需要用 this 指向 set 结构的属性方法

        // 解决 this 绑定指向错误
        let proxy = new Proxy(s, {
            get(target, key) {
                // 判断如果是方法,就修改this指向
                let value = target[key];
                if (value instanceof Function) {
                    // call apply bind
                    // 遇到 Function 都手动绑定一下 this,
                    // 使用 bind 绑定
                    return value.bind(target);
                    //不能 是 call apply
                }
                return value;
            },
            set() {
                console.log("set");
            }
        })
    </script>
</body>

</html>

在这里插入图片描述

Map结构

<!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>Proxy拦截不同数据结构</title>
</head>

<body>
    <script>
        let s = new Set();

        // let proxy = new Proxy(s, {
        //     get() {
        //         console.log("get");
        //     },
        //     set() {
        //         console.log("set");
        //     }
        // })
        // 使用 proxy.size 时可以打印 get,证明拦截成功
        // 但是使用 proxy.add 放方法就报错
        // 报错原因:get 方法没有做对方法的处理

        // 解决 get 方法没有做对方法的处理
        // let proxy = new Proxy(s, {
        //     get(target, key) {
        //         // console.log("get");
        //         return target[key];
        //     },
        //     set() {
        //         console.log("set");
        //     }
        // })
        // 正常调用 size,add 都没问题,
        // 但是在使用 add 方法时添加元素就报错
        // 报错原因: this 绑定指向错误,this 时指向 Proxy 代理,
        // 但是需要用 this 指向 set 结构的属性方法

        // 解决 this 绑定指向错误
        let proxy = new Proxy(s, {
            get(target, key) {
                // 判断如果是方法,就修改this指向
                let value = target[key];
                if (value instanceof Function) {
                    // call apply bind
                    // 遇到 Function 都手动绑定一下 this,
                    // 使用 bind 绑定
                    return value.bind(target);
                    //不能 是 call apply
                }
                return value;
            },
            set() {
                console.log("set");
            }
        })

        let m = new Map();
        let proxys = new Proxy(m, {
            get(target, key) {
                // 判断如果是方法,就修改this指向
                let value = target[key];
                if (value instanceof Function) {
                    // call apply bind
                    // 遇到 Function 都手动绑定一下 this,
                    // 使用 bind 绑定
                    return value.bind(target);
                    //不能 是 call apply
                }
                return value;
            },
            set() {
                console.log("Map");
            }
        })
    </script>
</body>

</html>

在这里插入图片描述

Proxy本质上属于元编程非破坏性数据劫持,在原对象的基础上进行了功能的衍生而又不影响原对象,符合松耦合高内聚的设计理念

15. Reflect对象

Reflect 可以用于获取目标对象的行为,它与 Object 类似,但是更易读,为操作对象提供了一种更优雅的方式

它的方法与 Proxy 是对应的

ES6 中将 Object 的一些明显属于语言内部的方法移植到了 Reflect 对象上(当前某些方法会同时存在于 Object 和 Reflect 对象上),未来的新方法会只部署在 Reflect 对象上

Reflect 对象对某些方法的返回结果进行了修改,使其更合理

Reflect 对象使用函数的方式实现了 Object 的命令式操作

15.1 代替Object的某些方法

<!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>Reflect对象代替Object的某些方法</title>
</head>

<body>
    <script>
        let obj = {};
        // Object.defineProperties(obj,"name",{
        Reflect.defineProperty(obj, 'name', {
            value: 'ich',
            writable: false, // 不可以修改
            configurable: false // 不可以删除
        });
    </script>
</body>

</html>

在这里插入图片描述

15.2 修改某些Object方法返回结果

// 老写法
// 因为 Object 方法 出现报错后,会中断
// 因此需要 try...catch 来捕获异常
try {
  Object.defineProperty(target, property, attributes);
  // success
} catch (e) {
  // fail
}

// 新写法
// 用 Reflect 方法出现报错会返回 false
// 让程序更合理
if (Reflect.defineProperty(target, property, attributes)) {
  // success
} else {
  // fail
}

当 Object 的 writable、enumerable 任意一个为 false 时,重复定义属性会报错

<!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方法返回结果</title>
</head>

<body>
    <script>
        // let obj = {};
        // Object.defineProperty(obj, "name", {
        //     value: "ich",
        //     // writable: true,
        //     // enumerable: true
        //     writable: false,
        //     enumerable: false
        // })

        // let res = Object.defineProperty(obj, "name", {
        //     value: "du"
        // })

        // console.log(res);

        // 改为 Reflect - 不会提示报错,只不过会返回 false 返回值,优点不会打断代码运行
        let obj = {};
        // Object.defineProperty(obj, "name", {
        Reflect.defineProperty(obj, "name", {
            value: "ich",
            // writable: true,
            // enumerable: true
            writable: false,
            enumerable: false
        })

        let res = Reflect.defineProperty(obj, "name", {
            value: "du"
        })

        console.log(res);
    </script>
</body>

</html>

在这里插入图片描述

15.3 命令式变为函数行为

对于一些命令式的 Object 行为,Reflect 对象可以将其变为函数式的行为

<!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>
</head>
<body>
    <script>
        let obj = {
            name: "ich"
        }

        console.log("name" in obj);
    </script>
</body>
</html>
const obj = {
    name:"kerwin"
};
//老写法
console.log("name" in obj) //true
//新写法
console.log(Reflect.has(obj, 'name')) //true

//老写法
delete obj.name
//新写法
Reflect.deleteProperty(obj, "name")

在这里插入图片描述

15.4 配合Proxy

<!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>配合Proxy</title>
</head>

<body>
    <script>
        // let obj = {
        //     name: "ich"
        // }

        // Reflect.set(obj, "age", 100);
        // console.log(Reflect.get(obj, "name"));

        let s = new Set();

        let proxy = new Proxy(s, {
            get(target, key) {
                // let value = target[key]
                // 用 Reflect 获取
                let value = Reflect.get(target, key)
                if (value instanceof Function) {
                    return value.bind(target)
                }
                return value
            },
            set(target, key, value) {
                // target[key] = value
                // console.log("set");
                // Reflect.set(target, key, value)
                // 简化
                Reflect.set(...arguments)
            }
        })
    </script>
</body>

</html>

在这里插入图片描述

配合解决数组数据

<!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>配合Proxy解决数组</title>
</head>

<body>
    <script>
        let arr = [1, 2, 3]

        let proxy = new Proxy(arr, {
            get(target, key) {
                return Reflect.get(...arguments)
            },
            set(target, key, value) {
                console.log("set", key, value);
                return Reflect.set(...arguments)
            }
        })
    </script>
</body>

</html>

在这里插入图片描述

GitHub代码
gitee代码

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

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

相关文章

2023年DAMA-CDGA/CDGP数据治理工程师认证这里报名

DAMA认证为数据管理专业人士提供职业目标晋升规划&#xff0c;彰显了职业发展里程碑及发展阶梯定义&#xff0c;帮助数据管理从业人士获得企业数字化转型战略下的必备职业能力&#xff0c;促进开展工作实践应用及实际问题解决&#xff0c;形成企业所需的新数字经济下的核心职业…

追梅西的少年

* * * 原创&#xff1a;刘教链 * * * 号外&#xff1a;今天在“刘教链Pro”发表了头条《鼠头和鸭脖——中心化验真的困境》&#xff0c;以及次条《内参&#xff1a;美SEC执法主管表示&#xff0c;DeFi是纯粹的欺诈&#xff01;&#xff1f;&#xff1f;》&#xff0c;欢迎关注…

云安全技术(六)之云架构模型

云架构模型 1.1 舍伍德业务应用安全架构(SABSA) 舍伍德业务应用安全架构(Sherwood Applied Business Security Architecture&#xff0c;SABSA)的官方网站是 。SABSA提供了一组组件&#xff0c;这些组件可部分或全部用作任何系统的安全架构方www.sabsa.org法。如下&#xff1a…

【Flutter】Flutter中如何获取子类Widget并调用它的方法

文章目录 一、前言二、理解 Flutter 中的 Widget三、如何在 Flutter 中获取子类 Widget1. 使用 GlobalKey2. 使用 context.findAncestorWidgetOfExactType 四、如何调用子类 Widget 的方法五、如何在 Flutter 中传递数据六、总结 一、前言 如果你想深入学习 Flutter&#xff0…

如何打造优秀Web3产品

近日&#xff0c;我们采访了Mysten Labs的联合创始人兼首席执行官Evan Cheng&#xff0c;探讨了Web3技术对消费者的价值、Web3行业应该如何更好地自我诠释&#xff0c;以及它对产品开发的影响。 您曾谈到Web3作为一种所有权实验&#xff0c;这种新技术可能会改变消费者的行为。…

Can’t connect to MySql server on ‘localhost’(10038)

一般是一下几个原因&#xff1a; 1、MySQL服务没有启动 2、用户没有权限使用远程连接 3、linux中防火墙中没有配置MySQL端口&#xff08;3306&#xff09; 使用命令service mysqld status 或者service mysql status 命令来查看mysql的启动状态 启动MySQL命令&#xff1a; …

±0.1℃精度、超低功耗的高精度数字模拟混合信号温度传感芯片

温度芯片感温原理基于CMOS半导体PN节温度与带隙电压的特性关系&#xff0c;经过小信号放大、模数转换数字校准补偿后&#xff0c;数字总线输出&#xff0c;具有精度高、一致性好、测温快、功耗低、可编程配置灵活、寿命长等优点。 温度芯片内置16-bit ADC&#xff0c;分辨率0.…

用代码生撸qsort函数来实现冒泡排序

作者主页&#xff1a;paper jie的博客_CSDN博客-C语言,算法详解领域博主 本文作者&#xff1a;大家好&#xff0c;我是paper jie&#xff0c;感谢你阅读本文&#xff0c;欢迎一建三连哦。 本文录入于《C语言》专栏&#xff0c;本专栏是针对于大学生&#xff0c;编程小白精心打造…

Windows 系统彻底卸载 SQL Server 通用方法

Windows 系统彻底卸载 SQL Server 通用方法 无论什么时候&#xff0c;SQL Server 的安装和卸载都是一件让我们头疼的事情。因为不管是 SQL Server 还是 MySQL 的数据库&#xff0c;当我们在使用数据库时因为未知原因出现问题&#xff0c;想要卸载重装时&#xff0c;如果数据库…

Jetson Xavier NX 备份与烧录固态系统

目录 1 需要的硬件 2 需要安装在ubuntu上的软件 2.1 安装gparted 2.2 安装nvidia官方烧录包 2.2.1 下载 2.2.2 配置 3 备份系统 4 烧入系统 1 需要的硬件 像是 nx&#xff0c;nx附带的固态硬盘&#xff0c;显示器 这些就赘述了 一个ubuntu实体机(虚拟机听说…

ansible-roles模块

roles用于层次性&#xff0c;结构化地组织playbook&#xff0c;roles能够根据层次型结构自动装载变量文件&#xff0c;tasks以及handlers等。要使用只要载playbook中使用include指令引入即可。 &#xff08;roles就是通过分别将变量&#xff0c;文件&#xff0c;任务&#xff…

u盘中毒文件夹数据丢失怎么恢复?这里有4个恢复方案

您是否曾经遇到过U盘中毒的情况&#xff1f;连累到文件夹内的数据文件消失了&#xff0c;如果丢失的是重要数据&#xff0c;这或许会对我们工作或学习带来了极大的困扰。为了解决您的困扰&#xff0c;下面将根据不同情况给予不同的U盘中毒数据恢复方案&#xff0c;帮助您尽快找…

小红书各行业流量分析:普通人怎么有效使用小红书?

随着互联网的发展&#xff0c;越来越多的人开始利用自媒体平台赚钱。小红书是近年来兴起的一种新型自媒体平台&#xff0c;也是国内最大的海外购物分享平台之一。随着小红书用户的不断增加&#xff0c;小红书的流量趋势也在发生着变化。那么&#xff0c;在各行业的流量趋势中&a…

驱动开发:文件微过滤驱动入门

MiniFilter 微过滤驱动是相对于SFilter传统过滤驱动而言的&#xff0c;传统文件过滤驱动相对来说较为复杂&#xff0c;且接口不清晰并不符合快速开发的需求&#xff0c;为了解决复杂的开发问题&#xff0c;微过滤驱动就此诞生&#xff0c;微过滤驱动在编写时更简单&#xff0c;…

XV-440-10TVB-1-50伊顿触摸屏EATON

​ XV-440-10TVB-1-50伊顿触摸屏EATON XV-440-10TVB-1-50伊顿触摸屏EATON ESD与dcs是完全分离的。DCS主要用于过程工业参数指标的动态控制。在正常情况下&#xff0c;DCS动态监控着生产过程的连续运行&#xff0c;保证能生产出符合要求的优良产品。而ESD则是对于一些关键的工艺…

python获取某博热搜数据并保存成Excel

python获取某博&#x1f9e3;热搜数据 一、获取目标、准备工作二、开始编码 一、获取目标、准备工作 1、获取目标&#xff1a; 本次获取教程目标&#xff1a;某博&#x1f9e3;热搜 2、准备工作 环境python3.xrequestspandas requests跟pandas为本次教程所需的库&#xff0c…

AM@空间曲面@平面@面面位置关系@点面距离

文章目录 曲面曲线平面点法式方程不共线的3点确定一个平面方程同解平面方程的一般式特别情形与坐标轴平行的平面与坐标轴垂直与坐标面平行的平面ABC0例 截距式两平面的夹角&#x1f47a;两平面的位置关系垂直关系平行关系例 点到平面的距离小结例 曲面 空间解析几何中"曲…

潜伏顶升AMR ∣解决方案背后——不断进化的市场和客户需求

潜伏顶升式AMR是通过潜入料架底部&#xff0c;利用升降机构提升料架&#xff0c;实现物料的输送;可支持货架、料车、笼车等多种载具,多用于物料架、物料车的转运。有效降低人力资源成本&#xff0c;减轻人工劳动强度。 作为移动机器人&#xff08;AMR/AGV&#xff09;近几年发展…

SpringBoot中集成Redis

目标 在原有SpringBoot项目中&#xff0c;集成Redis&#xff0c;并实现Dao层&#xff0c;Service层&#xff0c;Controller层。 pom.xml <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</…

大数据云计算运维之Nginx反向代理与负载均衡

Nginx 简介 一、Nginx概述 1.1 概述 Nginx&#xff08;“engine x”&#xff09;是一个高性能的 HTTP /反向代理的服务器及电子邮件&#xff08;IMAP/POP3)代理服务器。 官方测试nginx能够支撑5万并发&#xff0c;并且cpu&#xff0c;内存等资源消耗却非常低&#xff0c;运…