详解Reflect:Reflect和Object的异同,Reflect的一些内置方法以及方法注意点

news2024/11/18 15:44:13

Reflect

Reflect拥有Object对象的一些内部方法,某些方法会同时在Object对象和Reflect对象上部署,也就是说Object对象上存在的方法,通过Reflect也可以访问到。
单论Reflect的话,可以这么理解,Reflect就是继承了Object的某些内置方法,并且提供了优化

Object对象上的某些方法会有些缺陷,例如:在Object.defineProperty上对一个不可写或不可枚举的属性进行gettersetter时会抛出错误,对于这个错误,我们需要try catch去捕获,而Reflect.defineProperty则会抛出false来表示本次操作失败(Reflect对对象的操作都会抛出truefalse来表示是否操作成功)。
Object

const obj = { name : '东方不败' }
Object.defineProperty(obj,'age',{
    value : 100,
    writable : true,  // 只读
    configurable : false  // 不可删除和修改
})

Object.defineProperty(obj,'age',{
    get(){ return 200 }
})
console.log(obj.age); //  TypeError : Cannot redefine property: age
// 报错,不能重新定义属性

Reflect

const obj2 = { name : '西方求败' }
Object.defineProperty(obj2,'age',{
    value : 100,
    writable : true,  // 只读
    configurable : false  // 不可删除和修改
})

let status = Reflect.defineProperty(obj2,'age',{
    get(){ return }
})

console.log(status); //  false
console.log(obj2.age); // 100
// Reflect会抛出false表示此次操作失败

Object的部分操作是命令式的

let obj3 = {
    name : '东方不败',
    age : 100
}

console.log('name' in obj3);  // true
console.log(delete obj3.age);  // true
console.log(obj3);  // {name: '东方不败'}

Reflect的操作是函数式的

let obj4 = {
    name : '西方求败',
    age : 100
}

console.log(Reflect.has(obj4,'name'));  // true
console.log(Reflect.deleteProperty(obj4,'age')); // true
console.log(obj4);  // {name: '西方求败'}

通过上面的案例可以知道,Object内部的部分方法可以在Reflect上访问,Reflect对象一共有13个静态方法,如下:

1、Reflect.apply(target, thisArg, args)

2、Reflect.construct(target, args)

3、Reflect.get(target, name, receiver)

4、Reflect.set(target, name, value, receiver)

5、Reflect.defineProperty(target, name, desc)

6、Reflect.deleteProperty(target, name)

7、Reflect.has(target, name)

8、Reflect.ownKeys(target)

9、Reflect.isExtensible(target)

10、Reflect.preventExtensions(target)

11、Reflect.getOwnPropertyDescriptor(target, name)

12、Reflect.getPrototypeOf(target)

13、Reflect.setPrototypeOf(target, prototype)

下面是关于上面一些方法的使用解释

Reflect.get(target,name,receiver)

Reglect.get()有三个参数,分别是
1、target :目标对象
2、name:对象属性
3、receiver: 代理对象(可忽略)
作用:查找并返回target对象的name属性,如果该属性不存在则返回undefined

let o = {
    name : '东方',
    text : '不败'
}
console.log(Reflect.get(o,'name'));  // 东方

Reflect.set(target, name, value, receiver)

用于设置target对象的name属性等于value,如果修改成功返回true,失败返回false

  let o2 = {
    name : '艺术概论',
  }
// 如果这里设置为不可修改那么back 会输出false,price的值则为undefined
//   Object.defineProperty(o2,'price',{
//     configurable : false
//   })
  let back = Reflect.set(o2,'price',100)
  console.log(back); // true
  console.log(o2);  // {name: '艺术概论', price: 100}

Reflect.has(obj, name)

相当于Object里的in运算符,判断当前属性在目标对象内是否存在,true存在,false不存在

let o3 = {
    name : '中国工艺美术史'
}

console.log('name' in o3);  // true
console.log(Reflect.has(o3,'name')); // true

如果Reflect.has的第一个参数不是对象会报错


Reflect.deleteProperty(obj, name)

相当于Object的删除操作:delete obj.name,用于删除对象的属性

let o4 = {
    book : '疾风劲草',
    text : '一臂之力'
}
// Object
delete o4.book
console.log(o4);  // {text: '一臂之力'}
// Reflect
Reflect.deleteProperty(o4,'text')
console.log(o4);  // {}

Reflect.construct(target, args)

相当于new class(params),这里的Reflect可以不用new来创建调用构造函数的方法

function Person(name){
    this.name = name
}

// new 写法
let onNew = new Person('东方')

// Reflect.construct
let onNew2 = Reflect.construct(Person,['不败'])

Reflect.construct的第一个参数不是函数会报错


Reflect.getPrototypeOf(obj)

对应Object.getPrototypeOf(obj),用于读取对象的__proto__属性

let o5 = new String()

// Object.getPrototypeOf()
console.log(Object.getPrototypeOf(o5) == String.prototype); // true

// Reflect.getPrototypeOf()
console.log(Reflect.getPrototypeOf(o5) == String.prototype); // true

Reflect.setPrototypeOf(obj, newProto)

对应Object.setPrototypeOf(obj, newProto),用于设置目标对象的原型(prototype)

let o6 = {}
Reflect.setPrototypeOf(o6,Array.prototype)
console.log(o6.length);  // 0

Reflect.defineProperty(target, propertyKey, attributes)

相当于Object.definePropertyReflect.defineProperty()用来定义对象的属性。

let o7 = {
    name : '东方不败'
}

Reflect.defineProperty(o7,'age',{
    value : 100,
    configurable: true,
    enumerable : true,
    writable : true
})
console.log(o7);  // {name: '东方不败', age: 100}

如果Reflect.defineProperty()的第一个参数不是对象,会抛出错误。


Reflect.getOwnPropertyDescriptor(target, propertyKey)

对应Object.getOwnPropertyDescriptor,用来获得指定属性的描述对象

let o8 = {
    name : '东方不败'
}

Reflect.defineProperty(o8,'age',{
    value : 100,
    configurable: true,
    enumerable : true,
    writable : true
})

let back8 = Reflect.getOwnPropertyDescriptor(o8,'age')
console.log(back8);  // {value: 100, writable: true, enumerable: true, configurable: true}

在这里插入图片描述

如果Reflect.getOwnPropertyDescriptor()的第一个参数不是对象,会抛出错误。


Reflect.isExtensible (target)

相当于Object.isExtensible,返回布尔值,表示当前对象是否扩展

let o9 = {}
let back9 = Reflect.isExtensible(o9)
console.log(back9);  // true

如果参数不是对象会报错,非对象本来就是不可扩展的

console.log(Reflect.isExtensible(100));  // 报错

Reflect.preventExtensions(target)

相当于Object.preventExtensions,可以让目标对象变为不可扩展状态,返回布尔值表示是否设置成功

let b = {}
let info =  Reflect.preventExtensions(b)
console.log(info); // true
console.log(Reflect.isExtensible(b)); // false

如果参数不是对象会报错


Reflect.ownKeys (target)

用于返回目标对象的所有属性,包括Symbol

let address = Symbol.for('武汉')
let b2 = {
    name : '东方不败',
    age : 100,
    [address] : '世界城广场'
}

let info2 = Reflect.ownKeys(b2)
console.log(info2); // ['name', 'age', Symbol(武汉)]

如果Reflect.ownKeys ()的参数不是对象会报错


Reflect.apply(func, thisArg, args)

用于绑定this对象后执行给定函数。如果要给行数绑定一个this对象,可以使用apply的方式,但入股函数自己定义了自己的apply方法,就只能写成Function.prototype.apply.call(fn, obj, args)的方法嵌套,而Reflect则可以简化。

 let arr = [1,2,3,4,5,6,7]
 
 // 旧写法
 let a = Math.min.apply( Math, arr)
 let a2 = Math.max.apply( Math, arr)
 let a3 = Object.prototype.toString.call(a)
 console.log(a);   // 1
 console.log(a2);  // 7
 console.log(a3);  // [object Number]

 // 新写法
 let a4 = Reflect.apply( Math.min, Math, arr)
 let a5 = Reflect.apply( Math.max, Math, arr)
 let a6 = Reflect.apply( Object.prototype.toString, a4, [])
 console.log(a4);  // 1
 console.log(a5);  // 7
 console.log(a6);  // [object Number]
apply方法:
Function.apply(obj,args)方法能接收两个参数  
obj:这个对象将代替Function类里this对象
args:这个是数组,它将作为参数传给Function

事实上Reflect上存在的一些静态函数对应与ES2015之前的Object上可用的方法,尽管某些方法在行为上看起来相似,但它们之间常常存在着一些细微的差异。Reflect对象一共有13中静态方法,下表详细介绍了ObjectReflect API上可用方法之间的差异。请注意,如果API中不存在某种方法,则将其标记为N/A

方法ObjectReflect
defineProperty()Object.defineProperty() 返回传递给函数的对象。如果未在对象上成功定义属性,则返回TypeError。如果在对象上定义了属性,则Reflect.defineProperty()返回true,否则返回false。
defineProperties()Object.defineProperties() 返回传递给函数的对象。如果未在对象上成功定义属性,则返回TypeError。N/A
set()N/A如果在对象上成功设置了属性,则Reflect.set()返回true,否则返回false。如果目标不是Object,则抛出TypeError
get()N/AReflect.get()返回属性的值。如果目标不是Object,则抛出TypeError。
deleteProperty()N/A如果属性从对象中删除,则Reflect.deleteProperty()返回true,否则返回false。
getOwnPropertyDescriptor()如果传入的对象参数上存在Object.getOwnPropertyDescriptor() ,则会返回给定属性的属性描述符,如果不存在,则返回undefined。如果给定属性存在于对象上,则Reflect.getOwnPropertyDescriptor() 返回给定属性的属性描述符。如果不存在则返回undefined,如果传入除对象(原始值)以外的任何东西作为第一个参数,则返回TypeError
getOwnPropertyDescriptors()Object.getOwnPropertyDescriptors() 返回一个对象,其中包含每个传入对象的属性描述符。如果传入的对象没有拥有的属性描述符,则返回一个空对象。N/A
getPrototypeOf()Object.getPrototypeOf()返回给定对象的原型。如果没有继承的原型,则返回null。在 ES5 中为非对象抛出TypeError,但在 ES2015 中强制为非对象。Reflect.getPrototypeOf()返回给定对象的原型。如果没有继承的原型,则返回 null,并为非对象抛出TypeError。
setPrototypeOf()如果对象的原型设置成功,则Object.setPrototypeOf()返回对象本身。如果设置的原型不是Object或null,或者被修改的对象的原型不可扩展,则抛出TypeError。如果在对象上成功设置了原型,则Reflect.setPrototypeOf() 返回 true,否则返回 false(包括原型是否不可扩展)。如果传入的目标不是Object,或者设置的原型不是Object或null,则抛出TypeError。
isExtensible()如果对象是可扩展的,则 Object.isExtensible()返回 true,否则返回 false。如果第一个参数不是对象(原始值),则在 ES5 中抛出TypeError。在 ES2015 中,它将被强制为不可扩展的普通对象并返回false。如果对象是可扩展的,则Reflect.isExtensible() 返回true,否则返回false。如果第一个参数不是对象(原始值),则抛出TypeError。
preventExtensions()Object.preventExtensions() 返回被设为不可扩展的对象。如果参数不是对象(为原始值),则在 ES5 中抛出 TypeError。在 ES2015 中,则将参数视为不可扩展的普通对象,并返回对象本身。如果对象已变得不可扩展,则 Reflect.preventExtensions() 返回 true,否则返回 false。如果参数不是对象(为原始值),则抛出 TypeError。
keys()Object.keys()返回一个字符串数组,该字符串映射到目标对象自己的(可枚举)属性键。如果目标不是对象,则在 ES5 中抛出TypeError,但将非对象目标强制为 ES2015 中的对象N/A
ownKeys()N/AReflect.ownKeys()返回一个属性名称数组,该属性名称映射到目标对象自己的属性键。如果目标不是Object,则抛出TypeError。

上述表格的数据对比来源链接:比较 Reflect 和 Object 方法


案例源码:https://gitee.com/wang_fan_w/es6-science-institute

如果觉得这篇文章对你有帮助,欢迎点亮一下star哟

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

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

相关文章

C语言学习前序 - VS Code安装

要想学习一门编程语言,首先要有一个好的编程工具,推荐大家使用VS Code。 截止到现在,是我最喜欢的代码编辑工具。 工具下载。 官网地址:https://code.visualstudio.com/ 开始下载了,但是很慢很慢。 下载很慢可以直…

【Leetcode面试常见题目题解】4. 盛最多水的容器

题目描述 本文是LC第11题:盛最多水的容器。 题目描述如下: 给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。 找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多…

.Net 线程安全 (细粒度锁定、无锁机制以及lock)

.Net 线程安全最省事的lock关键字线程安全对象测试环境例子使用Queue源码和结果运行效果使用ConcurrentQueue的源码和结果运行效果volatile关键字易失性内存和非易失性内存的区别易失性内存:非易失性内存:volatile 关键字可应用于以下类型的字段&#xf…

<C++>AVL数

文章目录1. AVL树的概念2. AVL树节点的定义3. AVL树的插入4. AVL树的旋转5. AVL树的验证6. AVL树的性能1. AVL树的概念 二叉搜索树虽可以缩短查找的效率,但如果数据有序或接近有序二叉搜索树将退化为单支树,查找元素相当于在顺序表中搜索元素&#xff0…

MySQL中alter命令知识

MySQL中alter命令知识 文章目录MySQL中alter命令知识(一) 删除、添加、修改字段1、删除表中的字段数据2、添加新字段指定字段插入位置3、修改字段类型和名称(二)、修改表名(三)、修改存储引擎创建copy_emp表,便于后面案…

Prompt Learning 简介

最近去参会,看到了大量关于Prompt相关的论文,或者说跟NLP NLU相关的新论文或多或少都使用到了Prompt learning的一些思想或者设置。由于本人主业不是是做NLP的,所以对NLP顶会的这一现象觉得很有意思,趁闲暇学习了一下Prompt learn…

对话 BitSail Contributor | 姚泽宇:新生火焰,未来亦可燎原

2022 年 10 月,字节跳动 BitSail 数据引擎正式开源。同期,社区推出 Contributor 激励计划第一期,目前已有 12 位开发者为 BitSail 社区做出贡献,成为了首批 BitSail Contributor。 江海的广阔是由每一滴水珠构成的,Bi…

【高阶数据结构】手撕哈希表(万字详解)

🌈欢迎来到数据结构专栏~~手撕哈希表 (꒪ꇴ꒪(꒪ꇴ꒪ )🐣,我是Scort目前状态:大三非科班啃C中🌍博客主页:张小姐的猫~江湖背景快上车🚘,握好方向盘跟我有一起打天下嘞!送给自己的一句…

【jqgrid篇】jqgrid.setCell 改变单元格的值 改变单元格的样式设置单元格属性

setCellrowid,colname, data, class, propertiesjqGrid对象 改变单元格的值。rowid:当前行id;colname:列名称,也可以是列的位置索引,从0开始;data:改变单元格的内容,如果为空则不更 …

将GO、Pathway富集结果整合在一张高颜值圆圈图上

富集分析是生物医学论文中非常常见的一类分析,例如GO富集分析,Pathway富集分析等。其结果一般包括以下几个要素:1,名字(GO term或者KEGG description);2,该名字所包含的基因数目&…

400G数据中心短距离传输方案:400G QSFP-DD SR8光模块

随着更快、更高可靠性的网络需求增加,400G将是下一代骨干网升级和新建设的方向。400G光模块在构建400G网络系统中起着至关重要的作用。前面我们为大家介绍了短距离单模应用的400G QSFP-DD DR4光模块,本期文章,我们一起来了解一下短距离多模光…

自定义类型:结构体,枚举,联合(2)

TIPS 1. 类型的定义可以考虑放在头文件里头。 2. 一个汉字存储的时候占两个字节空间 3. 关于结构体变量初始化的一些细节 4. 关于结构体内存对齐的补充 1. 2. S1和S2类型的成员一模一样,但是S1和S2所占空间的大小有了一些区别。 3. 这两个结构体类型成员都…

【Linux】六、Linux 基础IO(一)|重谈文件|C语言文件操作|操作系统文件操作(系统文件I/O)|文件描述符

目录 一、重谈文件 二、C语言文件操作 2.1 重谈C语言文件操作 2.2 补充细节 三、操作系统文件操作(系统文件I/O) 3.1 文件相关系统调用:close 3.2 文件相关系统调用:open 3.2.1 open 的第二个参数 flags 3.2.2 open 的第…

解决跨微服务调用token共享问题

场景描述 使用jeecg搭建SpringCloud微服务系统模块,各个系统模块单独创建了拦截器进行权限校验。结果发现跨微服务调用存在鉴权失败问题。不能正常跨微服务调用。 原因描述 单个微服务鉴权拦截器。 package org.jeecg.modules.taxation.inerceptor;import org.s…

【MySQL】MySQL单表操作

序号系列文章2【MySQL】MySQL基本操作详解3【MySQL】MySQL基本数据类型4【MySQL】MySQL表的七大约束5【MySQL】字符集与校对集详解文章目录MySQL单表操作1,数据操作1.1,复制表结构和数据1.2,解决主键冲突1.3,清空数据1.4&#xff…

二叉树详解(概念+遍历实现)

一、基本概念 1.最左孩子结点:一个结点的孩子结点中位于最左边的孩子结点。例如,A——B,B——E; 2.树的高度:树的最高层数; 3.路径长度:树中的任意两个顶点之间都存在唯一的一条路径。一条路径所…

我们这样做容器分层性能测试

前言目前闲鱼不少业务正在从H5/Weex升级到Kun(基于W3C标准&Flutter打造的混合高性能终端容器),从测试角度来看,我们希望这种升级迭代对于用户体验是正向的,所以用好性能测试这把标准尺就显得格外重要。早期做性能保…

有什么比较好用的低代码开发平台?

国内有特色的低代码快速开发平台产品有哪些?这篇就来介绍下目前市面上主要的几家零代码开发平台! 简道云、明道云、IVX这几家目前是无代码赛道的明星选手,在市场综合表现上名列前茅。宜创、红圈营销虽也极具潜力,但在市场表现力上…

Java开发技术之成为高级java工程师必须学习的三个技术

所谓的Java高级程序员往往是经验和能力的结合,并不是说掌握了哪几个技术就是高级程序员了,能否把掌握的知识运用到实际的项目中,并且解决了具体的问题,这个才是衡量一个Java程序员的标准。 那么对于一名Java程序员来说&#xff0…

Java项目:房屋租赁系统设计和实现(java+ssm+mysql+spring+jsp)

源码获取:博客首页 "资源" 里下载! 主要功能描述: 1.登录管理:主要有管理员登录和租客登录 2.房源列表以及添加房源功能: 3.租赁合同管理以及在租房源和已退租房源信息管理: 4.看房申请和退租申请管理&a…