热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

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

💻【JavaScript】数据劫持(代理)详解🏠专栏:JavaScript👀个人主页:繁星学编程

💻 【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&#61;"box"></div>
<input type&#61;"text" id&#61;"ipt1">
<input type&#61;"text" id&#61;"ipt2">
<!-- 分割线 -->
// 原始数据
const obj &#61; {
name: &#39;zs&#39;,
age: 20
}
// 目标数据
const target &#61; {}
// 通过数据劫持的方法&#xff0c;把原始数据复制到目标中
Object.defineProperty(target, &#39;name&#39;, {
get() {
return obj.name
},
set(val) {
obj.name &#61; val
box.innerHTML &#61; &#96;你好&#xff0c; 我叫${target.name} , 我今年${target.age}&#96;
}
})
Object.defineProperty(target, &#39;age&#39;, {
get() {
return obj.age
},
set(val) {
obj.age &#61; val
box.innerHTML &#61; &#96;你好&#xff0c; 我叫${target.name} , 我今年${target.age}&#96;
}
})
box.innerHTML &#61; &#96;你好&#xff0c; 我叫${target.name} , 我今年${target.age}&#96;
ipt1.onchange &#61; function () {
target.name &#61; this.value
}
ipt2.onchange &#61; function () {
target.age &#61; this.value
}

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

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

效果图&#xff1a;

请添加图片描述

四. 数据代理(Proxy)

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

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

语法&#xff1a;

const p &#61; new Proxy(target, handler)

参数&#xff1a;

  • target


    要使用 Proxy 包装的目标对象&#xff08;可以是任何类型的对象&#xff0c;包括原生数组&#xff0c;函数&#xff0c;甚至另一个代理&#xff09;。

  • handler


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

简单的数据代理案例&#xff1a;

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

五. Proxy和Object.defineProperty的区别


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

结束语&#xff1a;

希望对您有一点点帮助&#xff0c;如有错误欢迎小伙伴指正。
&#x1f44d;点赞&#xff1a;您的赞赏是我前进的动力&#xff01;
⭐收藏&#xff1a;您的支持我是创作的源泉&#xff01;
✍评论&#xff1a;您的建议是我改进的良药&#xff01;
一起加油&#xff01;&#xff01;&#xff01;&#x1f4aa;&#x1f4aa;&#x1f4aa;







推荐阅读
  • 如何自行分析定位SAP BSP错误
    The“BSPtag”Imentionedintheblogtitlemeansforexamplethetagchtmlb:configCelleratorbelowwhichi ... [详细]
  • vue使用
    关键词: ... [详细]
  • Java序列化对象传给PHP的方法及原理解析
    本文介绍了Java序列化对象传给PHP的方法及原理,包括Java对象传递的方式、序列化的方式、PHP中的序列化用法介绍、Java是否能反序列化PHP的数据、Java序列化的原理以及解决Java序列化中的问题。同时还解释了序列化的概念和作用,以及代码执行序列化所需要的权限。最后指出,序列化会将对象实例的所有字段都进行序列化,使得数据能够被表示为实例的序列化数据,但只有能够解释该格式的代码才能够确定数据的内容。 ... [详细]
  • 目录实现效果:实现环境实现方法一:基本思路主要代码JavaScript代码总结方法二主要代码总结方法三基本思路主要代码JavaScriptHTML总结实 ... [详细]
  • 如何使用Java获取服务器硬件信息和磁盘负载率
    本文介绍了使用Java编程语言获取服务器硬件信息和磁盘负载率的方法。首先在远程服务器上搭建一个支持服务端语言的HTTP服务,并获取服务器的磁盘信息,并将结果输出。然后在本地使用JS编写一个AJAX脚本,远程请求服务端的程序,得到结果并展示给用户。其中还介绍了如何提取硬盘序列号的方法。 ... [详细]
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • Mac OS 升级到11.2.2 Eclipse打不开了,报错Failed to create the Java Virtual Machine
    本文介绍了在Mac OS升级到11.2.2版本后,使用Eclipse打开时出现报错Failed to create the Java Virtual Machine的问题,并提供了解决方法。 ... [详细]
  • 在说Hibernate映射前,我们先来了解下对象关系映射ORM。ORM的实现思想就是将关系数据库中表的数据映射成对象,以对象的形式展现。这样开发人员就可以把对数据库的操作转化为对 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • Voicewo在线语音识别转换jQuery插件的特点和示例
    本文介绍了一款名为Voicewo的在线语音识别转换jQuery插件,该插件具有快速、架构、风格、扩展和兼容等特点,适合在互联网应用中使用。同时还提供了一个快速示例供开发人员参考。 ... [详细]
  • 1,关于死锁的理解死锁,我们可以简单的理解为是两个线程同时使用同一资源,两个线程又得不到相应的资源而造成永无相互等待的情况。 2,模拟死锁背景介绍:我们创建一个朋友 ... [详细]
  • 本文介绍了lua语言中闭包的特性及其在模式匹配、日期处理、编译和模块化等方面的应用。lua中的闭包是严格遵循词法定界的第一类值,函数可以作为变量自由传递,也可以作为参数传递给其他函数。这些特性使得lua语言具有极大的灵活性,为程序开发带来了便利。 ... [详细]
  • 基于layUI的图片上传前预览功能的2种实现方式
    本文介绍了基于layUI的图片上传前预览功能的两种实现方式:一种是使用blob+FileReader,另一种是使用layUI自带的参数。通过选择文件后点击文件名,在页面中间弹窗内预览图片。其中,layUI自带的参数实现了图片预览功能。该功能依赖于layUI的上传模块,并使用了blob和FileReader来读取本地文件并获取图像的base64编码。点击文件名时会执行See()函数。摘要长度为169字。 ... [详细]
  • 本文讨论了如何优化解决hdu 1003 java题目的动态规划方法,通过分析加法规则和最大和的性质,提出了一种优化的思路。具体方法是,当从1加到n为负时,即sum(1,n)sum(n,s),可以继续加法计算。同时,还考虑了两种特殊情况:都是负数的情况和有0的情况。最后,通过使用Scanner类来获取输入数据。 ... [详细]
  • 本文介绍了在Linux下安装Perl的步骤,并提供了一个简单的Perl程序示例。同时,还展示了运行该程序的结果。 ... [详细]
author-avatar
手机用户2502856053
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有