ES6中的Proxy和Reflect内容详解

监听对象的操作

我们先来看一个需求:有一个对象,我们希望监听这个对象中的属性被设置或获取的过程

  • 通过我们前面所学的知识,能不能做到这一点呢?
  • 其实是可以的,我们可以通过之前的属性描述符中的存储属性描述符来做到;

监听对象的操作:下面这段代码就利用了前面讲过的 Object.defineProperty 的存储属性描述符来对属性的操作进行监听。

const obj={name:'liu',age:21
}Object.keys(obj).forEach(item=>{let value=obj[item]Object.defineProperty(obj,item,{get:function(){console.log('获取属性被监听了')return value},set:function(newValue){console.log('设置属性被监听了')value=newValue}})
})
obj.name='lilei'
obj.age=40
console.log(obj.name)
console.log(obj.age)

但是这样做有什么缺点呢?

  • 首先,Object.defineProperty设计的初衷,不是为了去监听截止一个对象的所有的属性的。我们在定义某些属性的时候,初衷其实是定义普通的属性,但是后面我们强行将它变成了数据属性描述符。
  • 其次,如果我们想监听更加丰富的操作,比如新增属性、删除属性,那么Object.defineProperty是无能为力的。
  • 所以我们要知道,存储数据描述符设计的初衷并不是为了去监听一个完整的对象。

Proxy基本使用

​ 在ES6中,新增了一个Proxy类,这个类从名字就可以看出来,是用于帮助我们创建一个代理的:也就是说,如果我们希望监听一个对象的相关操作,那么我们可以先创建一个代理对象(Proxy对象); 之后对该对象的所有操作,都通过代理对象来完成,代理对象可以监听我们想要对原对象进行哪些操作;

​ 我们可以将上面的案例用Proxy来实现一次:

  • 首先,我们需要new Proxy对象,并且传入需要侦听的对象以及一个处理对象,可以称之为handler; const p = new Proxy(target, handler)
  • 其次,我们之后的操作都是直接对Proxy的操作,而不是原有的对象,因为我们需要在handler里面进行侦听;
const obj={name:'liu',age:21
}const proxyObj=new Proxy(obj,{get:function(target,key,receiver){console.log('get方法被访问了----')return target[key]},set:function(target,key,newValue,receiver){console.log('set方法被访问了----')target[key]=newValue}
})console.log(proxyObj.name)
console.log(proxyObj.name='kobe')
console.log(proxyObj.age)
console.log(proxyObj.age=40)

Proxy的set和get捕获

如果我们想要侦听某些具体的操作,那么就可以在handler中添加对应的捕捉器(Trap):

set和get分别对应的是函数类型

set函数有四个参数:

  • target:目标对象(侦听的对象);
  • property:将被设置的属性key;
  • value:新属性值;
  • receiver:调用的代理对象;

get函数有三个参数:

  • target:目标对象(侦听的对象);
  • property:被获取的属性key;
  • receiver:调用的代理对象;

Proxy所有捕获器–13个

13个活捉器(捕捉器)分别是做什么的呢?

  • 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.ownKeys()----Object.getOwnPropertyNames 方法和Object.getOwnPropertySymbols 方法的捕捉器。
  • handler.has()----in 操作符的捕捉器。
  • handler.get()----属性读取操作的捕捉器。
  • handler.set()----属性设置操作的捕捉器。
  • handler.deleteProperty()----delete 操作符的捕捉器。
  • handler.apply()----函数调用操作的捕捉器。
  • handler.construct()----new 操作符的捕捉器。

Proxy的construct和apply

当然,我们还会看到捕捉器中还有construct和apply,它们是应用于函数对象的:

Reflect的作用

Reflect也是ES6新增的一个API,它是一个对象,字面的意思是反射

那么这个Reflect有什么用呢?

  • 它主要提供了很多操作JavaScript对象的方法,有点像Object中操作对象的方法;
  • 比如Reflect.getPrototypeOf(target)类似于 Object.getPrototypeOf();
  • 比如Reflect.defineProperty(target, propertyKey, attributes)类似于Object.defineProperty() ;

如果我们有Object可以做这些操作,那么为什么还需要有Reflect这样的新增对象呢?

  • 是因为在早期的ECMA规范中没有考虑到这种对 对象本身 的操作如何设计会更加规范,所以将这些API放到了Object上面;
  • 但是Object作为一个构造函数,这些操作实际上放到它身上并不合适;
  • 另外还包含一些类似于 in、delete操作符,让JS看起来是会有一些奇怪的;
  • 所以在ES6中新增了Reflect,让我们这些操作都集中到了Reflect对象上;

那么Object和Reflect对象之间的API关系,可以参考MDN文档:https://developer.mozilla.org/zhCN/docs/Web/JavaScript/Reference/Global_Objects/Reflect/Comparing_Reflect_and_Object_methods

Reflect的常见方法

Reflect中有哪些常见的方法呢?它和Proxy是一一对应的,也是13个:

  • Reflect.getPrototypeOf(target)-----类似于 Object.getPrototypeOf()。
  • Reflect.setPrototypeOf(target, prototype)-----设置对象原型的函数. 返回一个 Boolean, 如果更新成功,则返回true。
  • Reflect.isExtensible(target)-----类似于 Object.isExtensible()
  • Reflect.preventExtensions(target)-----类似于 Object.preventExtensions()。返回一个Boolean。
  • Reflect.getOwnPropertyDescriptor(target, propertyKey) -----类似于Object.getOwnPropertyDescriptor()。如果对象中存在该属性,则返回对应的属性描述符, 否则返回 undefined.
  • Reflect.defineProperty(target, propertyKey, attributes)-----和 Object.defineProperty() 类似。如果设置成功就会返回 true

Reflect的常见方法

  • Reflect.ownKeys(target)-----返回一个包含所有自身属性(不包含继承属性)的数组。(类似于Object.keys(), 但不会受enumerable影响).
  • Reflect.has(target, propertyKey) -----判断一个对象是否存在某个属性,和 in 运算符 的功能完全相同。
  • Reflect.get(target, propertyKey[, receiver])-----获取对象身上某个属性的值,类似于 target[name]。
  • Reflect.set(target, propertyKey, value[, receiver])-----将值分配给属性的函数。返回一个Boolean,如果更新成功,则返回true。
  • Reflect.deleteProperty(target, propertyKey) -----作为函数的delete操作符,相当于执行 delete target[name]。
  • Reflect.apply(target, thisArgument, argumentsList) -----对一个函数进行调用操作,同时可以传入一个数组作为调用参数。和Function.prototype.apply() 功能类似。
  • Reflect.construct(target, argumentsList[, newTarget])-----对构造函数进行 new 操作,相当于执行 new target(…args)。

Reflect的使用

那么我们可以将之前Proxy案例中对原对象的操作,都修改为Reflect来操作:

Receiver的作用

我们发现在使用getter、setter的时候有一个receiver的参数,它的作用是什么呢?

如果我们的源对象(obj)有setter、getter的访问器属性,那么可以通过receiver来改变里面的this

我们来看这样的一个对象

Reflect的construct

Proxy和Reflect内容详解相关推荐

  1. SQL Server DBA工作内容详解

    原文:SQL Server DBA工作内容详解 在Microsoft SQL Server 2008系统中,数据库管理员(Database Administration,简称为DBA)是最重要的角色. ...

  2. matlab的NLP功能,pyhanlp 共性分析与短语提取内容详解

    pyhanlp 共性分析与短语提取内容详解 简介 HanLP中的词语提取是基于互信息与信息熵.想要计算互信息与信息熵有限要做的是 文本分词进行共性分析.在作者的原文中,有几个问题,为了便于说明,这里首 ...

  3. java json path_Java使用JSONPath解析JSON完整内容详解

    JsonPath是一种简单的方法来提取给定JSON文档的部分内容. JsonPath有许多编程语言,如Javascript,Python和PHP,Java. JsonPath提供的json解析非常强大 ...

  4. 通过draggable实现布局_营销推广引流之百度霸屏内容详解 如何通过百度霸屏布局实现立体打法!...

    本篇文章主要讲一讲如何通过百度霸屏布局实现立体打法! 百度霸屏的内容详解 百度霸屏个人好做吗 营销推广引流之百度霸屏? 百度霸屏简单的讲就是当用户从百度搜索某个和你业务相关的关键词,如果页的位置可以出 ...

  5. 《方块方舟》自定义服务器工具,方舟方块世界怎么自建服务器 自建服务器方法内容详解-游侠网...

    方块方舟怎么自建服务器?很多玩家都想要自建立一个服务器,之前刚刚有了一个解决方案.小编就为大家整理好了方舟方块世界自建服务器方法内容详解,正在苦恼的玩家们还不快点进来看看? 游戏自建服务器方法内容解析 ...

  6. 命运2服务器维护2021,命运2 2021年3月17日更新内容详解 冰影系列削弱一览[多图]...

    命运2官方将在2021年3月17日的更新中对冰影系列进行削弱,部分玩家可能还不清楚,下面一起来看看命运2 2021年3月17日更新内容详解吧. 命运2 2021年3月17日更新内容详解 在3月17日即 ...

  7. 不思议迷宫 服务器维护,不思议迷宫精英服为什么进不去了 不思议迷宫精英服12月1日更新内容详解...

    不思议迷宫精英服为什么进不去了,很多玩家发现今天进不去精英服务器了,这是为什么呢?其实是因为更新,那么这次都有那些更新呢?很多玩家还不是特别清楚,今天小编便给大家带来不思议迷宫手游精英服务器12月1日 ...

  8. [转]netstat输出内容详解

    netstat 输出内容详解 1.列出所有 tcp与udp 端口 netstat  -anput Active Internet connections (servers and establishe ...

  9. netstat输出内容详解

    netstat 输出内容详解 1.列出所有 tcp与udp 端口 netstat  -anput Active Internet connections (servers and establishe ...

最新文章

  1. 浅谈对敏捷开发的初期理解
  2. css编写要注意什么 及一些公用的样式和外部引用 转码
  3. c语言实现补码加减,C语言实现用位移运算符进行加减乘…
  4. 内网linux服务器安装运行环境,linux下如何在内网中安装docker_网站服务器运行维护...
  5. 数据库-查看数据库-创建数数据库
  6. python多态_多态是什么?为什么要使用多态?
  7. matlab 矩阵jocobi迭代_第6章 解线性方程组的迭代法(基于MATLAB)
  8. Java 8.if语句
  9. 【智简联接,万物互联】华为云·云享专家董昕:Serverless和微服务下, IoT的变革蓄势待发
  10. Monad用简单的英语? (对于没有FP背景的OOP程序员)
  11. linux 修改ip地址 和关闭防火墙设置
  12. python微信刷屏_用python玩转微信
  13. 勤哲服务器仓库管理系统,用勤哲Excel服务器实现库存管理系统
  14. 微信小程序前端备忘录记事本搜索功能
  15. Redis爬坑记(一):incr命令和expire命令的误区
  16. 统计|如何理解多元线性回归的F检验的作用与目的
  17. 10年,从一个月薪2500的设备维修工,迫于压力转行,直到成为自动化测试专家···
  18. 京东API—获取京东商品详情
  19. SQL Server 修改数据库名、修改逻辑文件名、修改数据库物理文件名
  20. ISO 16750中的功能状态等级A-等级E分别是什么要求?

热门文章

  1. VMware 虚拟机的三种网络连接方式
  2. ORACLE中CLOB介绍及使用
  3. 分子对接教程 | (8) PyMOL可视化对接结果
  4. 【Html+CSS】3D旋转相册
  5. javascript_实现
  6. 先进控制技术+matlab仿真,先进 PID 控制及其 MATLAB 仿真(教材+相关程序) 刘金琨 著 电 子 工 业 出 版 社...
  7. Cannot use JSX unless the ‘--jsx‘ flag is provided.
  8. CF940E Cashback 题解
  9. 科教导刊杂志科教导刊杂志社科教导刊编辑部2022年第9期目录
  10. 第五章 如何使用java中的线程打印偶数和奇数