一、什么是反射机制

反射机制是在编译阶段不知道是哪个类被加载,而是在运行的时候才加载、执行。
也就是说,反射机制指的是程序在运行时能够获取自身的信息。
js 中的 apply 就是反射机制。

二、Reflect

1、Reflect 定义

Reflect 是一个内建的对象,用来提供方法去拦截 JavaScript 的操作。
Reflect 不是一个函数对象,所以它是不可构造的,也就是说它不是一个构造器,不能通过 new 操作符去新建或者将其作为一个函数去调用 Reflect 对象。
Reflect 的所有属性和方法都是静态的。

Reflect 内部封装了一系列对对象的底层操作
Reflect 成员方法就是 Proxy 处理对象的默认实现

const proxy = new Proxy(obj, {get(target, property) {// 如果没有定义 get 方法,那么默认返回的就是 Reflect 的 get 方法return Reflect.get(target, property)}
})

2、Reflect API 汇总

Reflect 提供了一套用于操作对象的 API,我们之前操作对象可以用 Object 上面的一些方法,也可以用 in、delete 这种操作符,使用 Reflect 就统一了操作方式

handler ⽅法 默认调⽤ 功能
get Reflect.get() 获取对象身上某个属性的值
set Reflect.set() 在对象上设置属性
has Reflect.has() 判断一个对象是否存在某个属性
deleteProperty Reflect.deleteProperty() 删除对象上的属性
getProperty Reflect.getPrototypeOf() 获取指定对象原型的函数
setProperty Reflect.setPrototypeOf() 设置或改变对象原型的函数
isExtensible Reflect.isExtensible() 判断一个对象是否可扩展 (即是否能够添加新的属性)
preventExtensions Reflect.preventExtensions() 阻止新属性添加到对象
getOwnPropertyDescriptor Reflect.getOwnPropertyDescriptor() 获取给定属性的属性描述符
defineProperty Reflect.defineProperty() 定义或修改一个对象的属性
ownKeys Reflect.ownKeys() 返回由目标对象自身的属性键组成的数组
apply Reflect.apply() 对一个函数进行调用操作,同时可以传入一个数组作为调用参数
construct Reflect.construct() 对构造函数进行 new 操作,实现创建类的实例
.preventExtensions Reflect.preventExtensions() 阻止新属性添加到对象

3、.apply()

Reflect.apply(target, thisArgument, argumentsList)

  • target:目标函数(必选)
  • thisArgument:target 函数调用时绑定的 this 对象(可选)
  • argumentsList:target 函数调用时传入的实参列表,该参数应该是一个类数组的对象(可选)

① ES5 用法

先指定方法,再去调用 apply

Math.floor.apply(null, [1.72])  // 1

② ES6 用法

先传递 apply,再指定是哪个方法

Reflect.apply(Math.floor, null, [1.72])  // 1

静态扫描时 Math.floor 是没有被执行,等到运行时再动态的将 Math.floor 作为参数传进来的

③ 实际应用

// ES5 用法
let price = 101.5
if (price > 100) {price = Math.floor.apply(null, [price])
} else {price = Math.ceil.apply(null, [price])
}price  // 101
// ES6 用法
let price = 101.5Reflect.apply(price > 100 ? Math.floor : Math.ceil, null, [price])  // 101

4、.construct()

使用反射的方式去实现创建类的实例,类似于 new target(…args)
Reflect.construct(target, argumentsList[, newTarget])

  • target:被运行的目标函数(必选)
  • argumentsList:调用构造函数的数组或者伪数组(可选)
  • newTarget:该参数为构造函数, 参考 new.target 操作符,如果没有 newTarget 参数, 默认和 target 一样(可选)

① ES5 用法

let a = new Date()a.getTime()  // 1632632744483

② ES6 用法

let b = Reflect.construct(Date, [])b.getTime()  // 1632632744484

5、.defineProperty()

静态方法 Reflect.defineProperty() 基本等同于 Object.defineProperty() 方法
Reflect.defineProperty(target, propertyKey, attributes)

  • target:目标对象(必选)
  • propertyKey:要定义或修改的属性的名称(可选)
  • attributes:要定义或修改的属性的描述(可选)

① ES5 用法

const student = {}
const r = Object.defineProperty(student, 'name', { value: 'Mike' })student  // {name: "Mike"}
r  // {name: "Mike"}

② ES6 用法

const student = {}
const r = Reflect.defineProperty(student, 'name', { value: 'Mike' })student  // {name: "Mike"}
r  // true

这两个方法效果上来看是一摸一样的,都可以改变一个对象的值
区别在于返回值不同:Object是返回这个值,Reflect是返回true

PS: 在 W3C 中,以后所有的 Object 上面的方法,都会慢慢迁移到 Reflect 对象,可能以后会在 Object 上面移除这些方法

6、.deleteProperty()

Reflect.deleteProperty 允许你删除一个对象上的属性,返回一个 Boolean 值表示该属性是否被成功删除,它几乎与非严格的 delete operator 相同
Reflect.deleteProperty(target, propertyKey)

  • target:删除属性的目标对象
  • propertyKey:将被删除的属性的名称

① ES5 用法

const obj = { x: 1, y: 2 }
const a = delete obj.xobj  // {y: 2}
a  // true

② ES6 用法

const obj = { x: 1, y: 2 }
const a = Reflect.deleteProperty(obj, 'x')obj  // {y: 2}
a  // true

7、.get()

Reflect.get() 方法的工作方式,就像从 object (target[propertyKey]) 中获取属性,但它是作为一个函数执行的
Reflect.get(target, propertyKey[, receiver])

① ES5 用法

const obj = { x: 1, y: 2 }obj.x  // 1
obj['x']  // 1

② ES6 用法

const obj = { x: 1, y: 2 }Reflect.get(obj, 'x')  // 1Reflect.get(['a', 'b', 'c'], 1)  // b

8、.getOwnPropertyDescriptor()

静态方法 Reflect.getOwnPropertyDescriptor() 与 Object.getOwnPropertyDescriptor() 方法相似
如果在对象中存在,则返回给定的属性的属性描述符,否则返回 undefined
Reflect.getOwnPropertyDescriptor(target, propertyKey)

① ES5 用法

const obj = { x: 1, y: 2 }Object.getOwnPropertyDescriptor(obj, 'x')
// {value: 1, writable: true, enumerable: true, configurable: true}

② ES6 用法

const obj = { x: 1, y: 2 }Reflect.getOwnPropertyDescriptor(obj, 'x')
// {value: 1, writable: true, enumerable: true, configurable: true}Reflect.getOwnPropertyDescriptor({ x: 'hello' }, 'y')
// undefinedReflect.getOwnPropertyDescriptor([], 'length')
// {value: 0, writable: true, enumerable: false, configurable: false}

③ 对比

如果 Reflect.getOwnPropertyDescriptor 的第一个参数不是一个对象(一个原始值),那么将造成 TypeError 错误
而对于 Object.getOwnPropertyDescriptor,非对象的第一个参数将被强制转换为一个对象处理

Reflect.getOwnPropertyDescriptor("foo", 0);
// TypeError: "foo" is not non-null objectObject.getOwnPropertyDescriptor("foo", 0);
// { value: "f", writable: false, enumerable: true, configurable: false }

9、.getPrototypeOf()

静态方法 Reflect.getPrototypeOf() 与 Object.getPrototypeOf() 方法是一样的,都是返回指定对象的原型(即,内部的 [[Prototype]] 属性的值)
Reflect.getPrototypeOf(target)

① ES5 用法

const d = New Date()Object.getPrototypeOf(d)
// {constructor: ƒ, toString: ƒ, toDateString: ƒ, toTimeString: ƒ, toISOString: ƒ, …}

② ES6 用法

const d = New Date()Reflect.getPrototypeOf(d)
// {constructor: ƒ, toString: ƒ, toDateString: ƒ, toTimeString: ƒ, toISOString: ƒ, …}

10、.has()

判断一个对象是否存在某个属性,和 in 运算符 的功能完全相同
Reflect.has(target, propertyKey)

const obj = { x: 1, y: 2 }Reflect.has(obj, 'x')  // true
Reflect.has(obj, 'z')  // false

11、.isExtensible()

判断一个对象是否可扩展
Reflect.isExtensible 与 Object.isExtensible 方法一样,都是判断一个对象是否可扩展 (即是否能够添加新的属性)
Reflect.isExtensible(target)

const obj = { x: 1, y: 2 }Reflect.isExtensible(obj)  // trueObject.freeze(obj)  // 阻止新属性添加到对象
obj.z = 3Reflect.isExtensible(obj)  // false
obj  // {x: 1, y: 2}

12、.ownKeys()

判断对象自身属性
Reflect.ownKeys 方法返回一个由目标对象自身的属性键组成的数组,它的返回值等同于 `Object.getOwnPropertyNames(target).concat(Object.getOwnPropertySymbols(target))
Reflect.ownKeys(target)

const obj = { x: 1, y: 2 }Reflect.ownKeys(obj)  // ["x", "y"]
Reflect.ownKeys([])  // ["length"]
Reflect.ownKeys([1, 2])  // ["0", "1", "length"]

13、.preventExtensions()

阻止新属性添加到对象,等同于Object.freeze()
Reflect.preventExtensions 方法阻止新属性添加到对象,例如:防止将来对对象的扩展被添加到对象中,与 Object.preventExtensions() 方法一致

Reflect.preventExtensions(target)

const obj = { x: 1, y: 2 }Reflect.isExtensible(obj)  // trueReflect.preventExtensions(obj)  // 阻止新属性添加到对象
obj.z = 3Reflect.isExtensible(obj)  // false
obj  // {x: 1, y: 2}

14、.set()

写数据
Reflect.set 方法允许你在对象上设置属性,用来给属性赋值,类似 property accessor 的语法,但它是以函数的方式
Reflect.set(target, propertyKey, value[, receiver])

const obj = { x: 1, y: 2 }
Reflect.set(obj, 'z', 4)obj  // {x: 1, y: 2, z: 4}const arr = ['apple', 'pear']
Reflect.set(arr, 1, 'banana')arr  // ["apple", "banana"]

15、.setPrototypeOf()

Reflect.setPrototypeOf 方法改变指定对象的原型 (即内部的 [[Prototype]] 属性值)
Reflect.setPrototypeOf(target, prototype)

const arr = ['apple', 'pear']
Reflect.getPrototypeOf(arr)
// [constructor: ƒ, concat: ƒ, copyWithin: ƒ, fill: ƒ, find: ƒ,…]Reflect.setPrototypeOf(arr, String.prototype)
Reflect.getPrototypeOf(arr)
// String {"", constructor: ƒ, anchor: ƒ, big: ƒ, blink: ƒ, …}

JS 反射机制及 Reflect 详解相关推荐

  1. JavaScript 反射机制及 Reflect 详解

    来自 | https://www.cnblogs.com/Leophen/archive/2021/06/02/14838608.html 一.什么是反射机制 反射机制是在编译阶段不知道是哪个类被加载 ...

  2. Proxy和Reflect详解

    Proxy和Reflect详解 之前一直没有理解proxy代理是啥意思,只是感觉很深奥的样子,最近正好在研究vue3的响应式原理,发现vue3是使用proxy完成响应式的,因此仔细的研究了一下prox ...

  3. Android-Binder进程间通讯机制-多图详解

    本系列: Android-Binder进程间通讯机制-多图详解 一次Binder通信最大可以传输多大的数据?​​​​​​​ 关于Binder (AIDL)的 oneway 机制 概述 最近在学习Bin ...

  4. jdbc mysql 自动重连_JDBC实现Mysql自动重连机制的方法详解

    JDBC是Java程序连接和访问各种数据库的API,它可以提供Java程序和各种数据库之间的连接服务,下面是爱站技术频道小编为大家带来的JDBC实现Mysql自动重连机制的方法详解. 日志:using ...

  5. js showModalDialog参数的使用详解(转)

    js showModalDialog参数的使用详解_javascript技巧_脚本之家 http://www.jb51.net/article/45281.htm 本篇文章主要是对js中showMod ...

  6. [js]JavaScript Number.toPrecision() 函数详解

    [js]JavaScript Number.toPrecision() 函数详解 JavaScript: numberObject.toPrecision( [ precision ] ) 如果没有提 ...

  7. 四叶草剧场服务器维修价格,四叶草剧场不合理报酬机制是什么-不合理报酬机制和收益详解-Appfound...

    四叶草剧场不合理报酬机制是什么?不合理报酬的增益效果怎么样?在四叶草剧场手游中,有一种剧照效果是不合理的报酬,会使敌方角色被施加减益效果时还会失去5%最大生命,下面就为大家详细介绍不合理报酬的机制和收 ...

  8. node mysql 查询_Node.js使用mysql进行查询详解

    本篇教程介绍了Node.js使用mysql进行查询详解,希望阅读本篇文章以后大家有所收获,帮助大家对Node.js的理解更加深入. < 因为返回的是个对象 var selectSql1=&quo ...

  9. js中小括号()的用法详解

    一.js中小括号()的用法详解 1.作为分组运算符: 分组运算符应该是再熟悉不过了,因为在小学数学中就有应用,例如: var a=(1+2)*4; console.log(a); 以上代码的输出值是1 ...

最新文章

  1. homework-03
  2. linux实时备份,51CTO博客-专业IT技术博客创作平台-技术成就梦想
  3. Apache web服务
  4. python源码精要(5)-C代码规范
  5. java安全编码指南之:线程安全规则
  6. matlab 小波变换_连续小波变换实现方法的总结及其程序详解
  7. 将DataFrame格式的数据存入到mysql数据库中
  8. 删除目录及目录下所有文件与子目录
  9. java textvaluechanged 全选删除不触发_js动态改变input的值不触发input的change事件的解决办法...
  10. 【Java 集合】ArrayList、LinkedList、Stack、Queue、Set、Map, 迭代器 Iterable、Iterator,Collections类
  11. 神经网络 demo(斯坦福)
  12. SSH和SSM的内容
  13. 原生JS实现登录框邮箱提示
  14. python抓取网页图片示例
  15. VBA打开一个EXCEL文件并在二个文件之间来回操作的代码
  16. 现代治理12.0:Diligent发出“现代领导力”倡议,帮助组织创建更具多元化和包容性的董事会和领导团队
  17. 什么是大数据分析 主要应用于哪些行业?
  18. 清理工作区git clean -fd
  19. 记录一次mongoDB错误 errmsg: cannot use the part () to traverse the element
  20. 【C++】-命名空间的概念及使用

热门文章

  1. 惠惠软件|小程序在餐饮行业的应用经验
  2. 5G的网络架构:Option3 Option3A Option3X
  3. MATLAB 得心应手的成长之路 (一) 数据的筛选
  4. CSS设置div与屏幕高度一致
  5. 计算机科学与技术杨晓静,杨晓静
  6. API HOOK技术
  7. c语言关于sqrt判断素数原理的理解
  8. 2021信息安全工程师学习笔记(二)
  9. 数学建模之偏最小二乘回归分析
  10. 【UE Niagara】实现简单的下雪、下雨天气效果