【JavaScript】数据劫持(代理)详解

news2024/12/24 21:44:33

💻 【JavaScript】数据劫持(代理)详解 🏠专栏:JavaScript
👀个人主页:繁星学编程🍁
🧑个人简介:一个不断提高自我的平凡人🚀
🔊分享方向:目前主攻前端,其他知识也会阶段性分享🍀
👊格言:☀️没有走不通的路,只有不敢走的人!☀️
👉让我们一起进步,一起成为更好的自己!!!🎁

文章目录

  • 【JavaScript】数据劫持(代理)
    • 一. Object.defineProperty()
    • 二. 数据劫持
    • 三. 封装函数实现数据劫持
    • 四. 数据代理(Proxy)
    • 五. Proxy和Object.defineProperty的区别

【JavaScript】数据劫持(代理)

所谓数据代理(也叫数据劫持),指的是在访问或者修改对象的某个属性时,通过一段代码拦截这个行为,进行额外的操作或者修改返回结果。比较典型的是 Object.defineProperty() 和 ES2015 中新增的 Proxy 对象。而在前端框架中vue2.0使用的是Object.defineProperty()、vue3.0使用的是Proxy。当然今天主要讲述的JS和ES中的数据劫持,vue中的小编后续会安排上。

一. Object.defineProperty()

语法:Object.defineProperty(数据, 属性名, {配置项})

配置项

  • value:设置属性名对应的属性值

  • writable:设置的属性是否可以修改

    值:true/false(默认)

  • enumerable:设置的属性是否可以遍历

    值:true/false (默认)

  • configurable:设置的属性是否可以删除

    值:true/false(默认)

  • getter、setter:不允许和value, writable连用,连用会报错

    • get 获取的时候可以触发的方法
    • set 设置的时候可以触发的方法

:value、writable、enumerable、configurable可以单独使用也可以连用

针对上述配置项的使用情况

(1) value

const obj = { name: "zs" }
Object.defineProperty(obj, "age", {
    // 设置属性名对应的属性值
    value: 20;
});
console.log(obj); // {name: 'zs', age: 20}
obj.age = 30;
console.log(obj); // {name: 'zs', age: 20}

(2) writable

const obj = { name: "zs" }
Object.defineProperty(obj, "age", {
    // 设置的属性可以修改 
    writable: true
})
console.log(obj); // { name: 'zs', age: undefined }
obj.age = 30;
console.log(obj); // {name: 'zs', age: 20}

(3) enumerable

const obj = { name: "zs" }
Object.defineProperty(obj, "age", {
    value: 20,
    // 设置的属性可以遍历 
    enumerable: true
});
for (let k in obj) {
    console.log(k, obj[k]); // name zs age 20
}

(4) configurable

const obj = { name: "zs" }
Object.defineProperty(obj, "age", {
    // 设置的属性可以删除  
    configurable: true
});
delete obj.name;
console.log(obj); // {age: undefined}

(5) get set定义属性

const obj = { name: "zs" }
Object.defineProperty(obj, "age", {
    get() {
        return 20; // 当我们设置一个返回值的时候,就表示该属性被设置了值
    },
    set(val) {
        // 可以监听到设置的值
        console.log(val); // 19
    }
});
obj.age = 19; // 设置的时候,会触发 set方法
console.log(obj.age); // 20 (获取的时候, 会触发 get方法)
console.log(obj);

二. 数据劫持

当访问或者修改对象的某个属性的时候,通过 getter setter 拦截这个行为,进行额外的操作
将原始的数据复制一份,通过复制的数据操作原始数据

<div id="box"></div>
<input type="text" id="ipt1">
<input type="text" id="ipt2">
<!-- 分割线 --> 
// 原始数据
const obj = {
    name: 'zs',
    age: 20
}
// 目标数据
const target = {}
// 通过数据劫持的方法,把原始数据复制到目标中
Object.defineProperty(target, 'name', {
    get() {
        return obj.name
    },
    set(val) {
        obj.name = val
        box.innerHTML = `你好, 我叫${target.name} , 我今年${target.age}`
    }
})
Object.defineProperty(target, 'age', {
    get() {
        return obj.age
    },
    set(val) {
        obj.age = val
        box.innerHTML = `你好, 我叫${target.name} , 我今年${target.age}`
    }
})
box.innerHTML = `你好, 我叫${target.name} , 我今年${target.age}`
ipt1.onchange = function () {
    target.name = this.value
}
ipt2.onchange = function () {
    target.age = this.value
}

三. 封装函数实现数据劫持

<div id="box"></div>
<input type="text" id="ipt1">
<input type="text" id="ipt2">
<script>
    // 原始对象
    const obj = {
        name: 'zs',
        age: 20
    }
    // 进行封装函数实现数据劫持
    function encapsulation(obj, cb) {
        // 目标对象
        // 通过数据劫持的方法,把原始数据复制到目标中
        let target = {};
        // 遍历原始对象,拿到对象中的每一个值
        for (let k in obj) {
            Object.defineProperty(target, k, {
                get() {
                    return obj[k];
                },
                set(val) {
                    obj[k] = val;
                    cb(target);
                }
            });
        }
        cb(target);
        return target;
    }
	// 调用封装函数
    let app = encapsulation(obj, (target) => {
        box.innerHTML = `你好, 我叫${target.name} , 我今年${target.age}`;
    });
    // 获取input框中输入的值
    ipt1.onchange = function () {
        app.name = this.value;
    }
    ipt2.onchange = function () {
        app.age = this.value;
    }
</script>

效果图

请添加图片描述

四. 数据代理(Proxy)

在数据劫持这个问题上,Proxy 可以被认为是 Object.defineProperty() 的升级版。外界对某个对象的访问,都必须经过这层拦截。因此它是针对 整个对象,而不是 对象的某个属性,所以也就不需要对 keys 进行遍历。

Proxy 对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)。

语法

const p = new Proxy(target, handler)

参数

  • target

    要使用 Proxy 包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)。

  • handler

    一个通常以函数作为属性的对象,各属性中的函数分别定义了在执行各种操作时代理 p 的行为。

简单的数据代理案例

const obj = {
    name: 'tom',
    age: 18
}
// 开始代理
const res = new Proxy(obj, {
    // 访问数据的时候 会触发
    get(target, property) {
        return target[property];
    },
    // 设置数据的时候会触发
    set(target, property, val) {
        // target 就是要代理的目标对象
        // property 就是要修改的属性
        // val 修改的属性值
        target[property] = val;
        // 必须写,简单代理必须返回true
        return true;
    }
})
res.name = 'jerry';
// 给对象新添加一个数据
res.sex = '女';
console.log('原始数据', obj); // 原始数据 {name: 'jerry', age: 18, sex: '女'}
console.log('代理结果', res); // 代理结果 Proxy {name: 'jerry', age: 18, sex: '女'}

五. Proxy和Object.defineProperty的区别

  1. Proxy是对整个对象的代理,而Object.defineProperty只能代理某个属性。
  2. 对象上新增属性,Proxy可以监听到,Object.defineProperty不能。
  3. 数组新增修改,Proxy可以监听到,Object.defineProperty不能。
  4. 若对象内部属性要全部递归代理,Proxy可以只在调用的时候递归,而Object.definePropery需要一次完成所有递归,性能比Proxy差。
  5. Proxy不兼容IE,Object.defineProperty不兼容IE8及以下
  6. Proxy使用上比Object.defineProperty方便多。

结束语

希望对您有一点点帮助,如有错误欢迎小伙伴指正。
👍点赞:您的赞赏是我前进的动力!
⭐收藏:您的支持我是创作的源泉!
✍评论:您的建议是我改进的良药!
一起加油!!!💪💪💪

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

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

相关文章

3万行代码硬撸一个一键发布文章工具,简直不要太好用,从此写文章,发文章,太简单了好伐

theme: channing-cyan highlight: github-gist 本人6年前端开发老鸟- 【程序员蜗牛】&#xff0c;欢迎沟通交流 操作演示&#xff08;视频&#xff09; 视频演示 项目背景 程序员工作中&#xff0c;不免会遇到一些技术难题&#xff0c;然后通过不懈努力将问题攻克&#xf…

1x1卷积、Inception网络、

目录1.1x1卷积(1x1 convolution)又称网络中的网络(network in network)池化层只能压缩图像的宽和高&#xff0c;1x1卷积能压缩通道数量&#xff0c;减少计算成本。如上图&#xff0c;输入维度的通道数为192&#xff0c;用32个1x1x192的filters&#xff0c;就能将输出的通道数压…

【Rust】20. Rust 的高级特征

20.1 不安全 Rust 20.1.1 不安全的超能力 20.1.2 解引用裸指针 裸指针&#xff08;raw pointers&#xff09;&#xff1a;类似于引用类型&#xff1b;和引用一样&#xff0c;裸指针是不可变或可变的&#xff0c;分别写作 *const T 和 *mut T&#xff0c;这里的星号不是解引用运…

Kubernetes集群部署与实践

一、提要 部署Kubernetes集群至少需要3台服务器&#xff0c;其中至少要有1个服务器做master节点&#xff0c;至少要有1个服务器做node节点&#xff0c;且节点名称是唯一的。 当集群中只有一个master节点时&#xff0c;如果其出现了故障&#xff0c;会导致Kubernetes的控制平面…

规则引擎-drools-5-决策表

文章目录Excel格式决策表 官网地址决策表使用方式Excel组成部分与drl规则文件对应关系Excel文件内容示例drl规则文件内容Excel决策表内容说明1. RuleSet2. RuleTable3. Attributes示例Excel转化drl代码及结果执行drl代码及结果Excel格式决策表 官网地址 决策表这部分内容在官网…

几种IO模型

IO真正的IO操作涉及到和IO设备的交互&#xff0c;而操作系统限制了应用程序直接和设备交互。我们通常说的IO操作实际上是应用程序和操作系统进行交互&#xff0c;一般会使用操作系统的System Call&#xff0c;即系统调用&#xff0c;读是read()&#xff0c;写是write()&#xf…

设计模式-结构型模式

目录 5.结构型模式 5.1 代理模式 5.1.1 概述 5.1.2 结构 5.1.3 静态代理 5.1.4 JDK动态代理 5.1.5 CGLIB动态代理 5.1.6 三种代理的对比 5.1.7 优缺点 5.1.8 使用场景 5.2 适配器模式 5.2.1 概述 5.2.2 结构 5.2.3 类适配器模式 5.2.4 对象适配器模式 5.2.5 应…

聊聊关于矩阵反向传播的梯度计算

目录 1. 前向传播 2. 反向传播 3. 矩阵反向传播 4. 总结 1. 前向传播 建立如图所示的简单网络 W 是权重矩阵&#xff0c;初始赋值为 2*2 的矩阵 X 是输入特征&#xff0c;初始赋值为 2*1 的矩阵 这样通过矩阵乘法 &#xff0c; Y WX &#xff0c;应该得到一个 2*1 的输…

在这竞争激烈的时代,如何才能够在激烈竞争中脱颖而出呢

不管是在职场想要获得认可得到晋升&#xff0c;还是与客户谈合作&#xff1b;都需要你能够脱颖而出。让他人能够看到你并且认可你。那如何才能脱颖而出呢&#xff1f;首先你要先认识自己&#xff0c;知道自己有什么优势、劣势、技能、兴趣、爱好等等。明确自己有什么价值&#…

软件工程(1)--初识基础概念

前言 学习了半年的软件工程课程&#xff0c;总不能一无所获吧&#xff0c;故此写下文章总结一番。 软件工程是一门综合性交叉学科&#xff0c;它涉及计算机科学、工程科学、管理科学和数学等领域。学习目标是掌握需求分析、软件设计、编码风格、软件测试的工程化方法。 软件程序…

什么是股票量化研究?

谈到股票量化研究领域&#xff0c;肯定少不了有自动交易系统的支撑&#xff0c;像平时能将股票池中的数据挖掘出来也能熟能生巧的进行自助量化研究&#xff0c;包括数据接口系统的开发使用都是受到量化的影响&#xff0c;那么&#xff0c;如何看待股票量化研究&#xff1f;像平…

arm版(以uos为例)linux安装mysql8

官网下载&#xff1a;https://downloads.mysql.com/archives/community/上传到服务器&#xff0c;然后解压缩tar -zxvf mysql-8.0.31-linux-glibc2.17-aarch64.tar.gzmv mysql-8.0.31-linux-glibc2.17-aarch64 /usr/local/mysql-8创建MySQL数据目录mkdir -p /datacd datamkdir …

打通对账的最后一公里——对账管理平台

背景 日新月异的科技与快速变化的消费需求不断驱动零售模式的变革&#xff0c;实体商业与数字经济、传统零售与新零售&#xff0c;逐渐融合并形成了全渠道、一体化的发展趋势&#xff0c;也改变了以往企业认知中线上、线下渠道割裂的思维定式&#xff0c;零售快消类企业纷纷建…

电子技术——MOS管的物理特性

电子技术——MOS管的物理特性 增强型 MOSFET 是应用最广泛的场效应晶体管。除了最后一节&#xff0c;我们整章讨论的都是增强型 MOSFET 。我们从它的物理元件结构和物理操作入手&#xff0c;在下一节我们会在本节的基础上学习 MOSFET 的电流-电压特性。 元件结构 上图展示了n-…

Day876.redolog刷盘问题 -MySQL实战

redolog刷盘问题 Hi&#xff0c;我是阿昌&#xff0c;今天学习记录的是关于redolog刷盘问题的内容。 平时的工作中&#xff0c;一条 SQL 语句&#xff0c;正常执行的时候特别快&#xff0c;但是有时也不知道怎么回事&#xff0c;它就会变得特别慢&#xff0c;并且这样的场景很…

RPA自动化办公07——Uibot流程加入python插件

参考&#xff1a;扩展UiBot命令_UiBot开发者指南 Uibot是非常方便&#xff0c;但是有些功能可能还需要别的语言来完成&#xff0c;例如python语言&#xff0c;作为胶水语言&#xff0c;在一个Uibot里面插入python脚本是很方便&#xff0c;好用的。 加入插件的位置 在新建一个流…

Seata分布式事务模式(TA、TCC、XA、SAGA)工作机制

前言 分布式应用痛点 分布式应用有一个比较明显的问题就是&#xff0c;一个业务流程通常需要几个服务来完成&#xff0c;业务的一致性很难保证。为了保障业务一致性&#xff0c;每一步都要在 catch 里去处理前面所有的“回滚”操作&#xff0c;可读性及维护性差&#xff0c;开…

分布式微服务

目录 认识微服务 单体服务架构的特点 分布式架构的特点 微服务 SpringCloud 总结 服务拆分及远程调用 服务拆分原则 假如在订单服务中&#xff0c;需要一起返回用户的信息 Eureka注册中心 Eureka的结构和作用 问题&#xff1a;order-service如何得知user-service实例…

基于拓扑的单树分割用于地面激光扫描点云的自动处理

Paper题目&#xff1a;Topology-based individual tree segmentation for automated processing of terrestrial laser scanning point clouds ABSTRACT 地面激光扫描 (TLS) 是一种基于地面的方法&#xff0c;可通过光探测和测距 (LiDAR) 技术快速获取 3D 点云。从 TLS 点云量…

搜索引擎关键字智能提示实践

为了提高阅读体验&#xff0c;请移步到&#xff1a;搜索引擎关键字智能提升实践一、背景搜索关键字智能提示是一个搜索应用的标配&#xff0c;主要作用是避免用户输入错误的搜索词&#xff0c;并将用户引导到相应的关键词上&#xff0c;以提升用户使用体验。雪球以连接人与资产…