深入浅出 JavaScript Reflect API

简介: 深入浅出 JavaScript Reflect API

深入浅出 JavaScript Reflect API

作为开发人员,你需要创建能够处理动态代码的系统和应用程序。这些程序应该能够在运行时操作变量、属性和对象方法。为此,ES6 中引入了一个新的全局对象 Reflect,它能够处理简单的代码操作。

本文的目的是帮助你更好地理解 JavaScript 中 Reflect 的概念以及如何使用提供的各种方法。Reflect 使你能够轻松地修改现有对象的功能,同时仍然提供其默认行为。

1. 什么是 JavaScript Reflect?

JavaScript Reflect 是一个内置的 ES6 全局对象,它提供了在运行时操作「属性」「变量」「对象方法」的能力。它不是构造函数,因此不能对它使用 new 操作符。

2. Proxy 和 Reflect 之间的区别?

ProxyReflect 都是在 ES6 中引入的,用于执行任务,但它们有一点不同。

Reflect 不同,JavaScript 的 Proxy 没有任何属性。相反,它封装另一个对象并拦截其操作。同时,Reflect 是一个内建对象,它简化了 Proxy 的创建,并使调用内部方法成为可能。

Proxy 只接受两个参数:

  • targetProxy 将包装处理程序的对象
  • handler:将拦截目标操作的代理配置

这里有一个例子:

const profile = { name: 'xiaan', age:21 }
const handler = {
 get(target, prop, receiver) {
   if (target[prop]) {
     return target[prop]
    }
    return `"${prop}" prop don't exist on this object !`
  }
}
const profileProxy = new Proxy (profile, handler)
console.log(profileProxy.name) // xiaan
console.log(profileProxy.profession) // "profession" prop don't exist on this object !

上面的例子等价于 Reflect.get(),后者将在本指南后面介绍,但是,Reflect.get() 技术更简单、更直接。

3. 使用 JavaScript Reflect API 的方法

让我们仔细看看 Reflect 对象的方法。所有这些方法都是静态的,也就是说,它们只能用于 Reflect 对象,而不能用于任何实例。

3.1 Reflect.construct()

Reflect.construct() 方法和 new 操作符有所差异,但与 new target(...args) 相似,它有选择不同原型的选项。Reflect.construct() 接受三个参数:

  • target:被运行的目标构造函数
  • args:类数组,目标构造函数调用时的参数
  • newTarget:一个可选的构造函数,作为新创建对象的原型对象的 constructor 属性,如果不指定,默认值为 target
  • 「返回值」:以 target(如果 newTarget 存在,则为 newTarget)函数为构造函数,argumentList 为其初始化参数的对象实例。

考虑下面的例子:

function summation(x,y,z){
  this.add = x + y +z
}
const sum = Reflect.construct(summation, [1,2,3,4,5])
console.log(sum)
// 结果: summation {add: 6}

Reflect.construct() 生成 targetnewTarget 的新实例(如果指定了),该实例是用提供的参数 args 数组构造的。在引入 Reflect.construct() 之前,我们将结合构造函数和原型来创建一个对象:object.create()

function OneClass() {
    this.name = 'one';
}
function OtherClass() {
    this.name = 'other';
}
// 创建一个对象
var obj1 = Reflect.construct(OneClass, args, OtherClass);
// 与上述方法等效
var obj2 = Object.create(OtherClass.prototype);
OneClass.apply(obj2, args);
console.log(obj1.name); // 'one'
console.log(obj2.name); // 'one'
console.log(obj1 instanceof OneClass); // false
console.log(obj2 instanceof OneClass); // false
console.log(obj1 instanceof OtherClass); // true
console.log(obj2 instanceof OtherClass); // true

虽然两种方式结果相同,但在创建对象过程中仍一点不同。 当使用 Object.create()Function.prototype.apply() 时,如果不使用 new 操作符调用构造函数,构造函数内部的 new.target 值会指向 undefined

当调用 Reflect.construct() 来创建对象,new.target 值会自动指定到 target(或者 newTarget,前提是 newTarget 指定了)。

function OneClass() {
    console.log('OneClass');
    console.log(new.target);
}
function OtherClass() {
    console.log('OtherClass');
    console.log(new.target);
}
var obj1 = Reflect.construct(OneClass, args);
// 输出:
//     OneClass
//     function OneClass { ... }
var obj2 = Reflect.construct(OneClass, args, OtherClass);
// 输出:
//     OneClass
//     function OtherClass { ... }
var obj3 = Object.create(OtherClass.prototype);
OneClass.apply(obj3, args);
// 输出:
//     OneClass
//     undefined

3.2 Reflect.apply()

Reflect.apply() 是一种使用提供的参数调用目标函数的简单而直接的方法。它包含三个参数:

  • target:要调用的函数
  • thisArgumenttarget 函数调用时绑定的 this 对象
  • argumentsListtarget 函数调用时传入的实参列表,该参数应该是一个类数组的对象
  • 「返回值:」 调用完带着指定参数和 this 值的给定的函数后返回的结果

让我们看看下面的例子:

const arr = [3,5,20,3,31]
const a = Reflect.apply(Math.max, undefined, arr)
console.log(a)
// 结果: 31

在引入 Reflect.apply() 之前,我们可以使用 Function.prototype.apply() 方法来执行类似的任务,如下所示:

const arr = [3,5,20,3,31]
const a = Function.prototype.apply.call(Math.max, undefined, arr);
console.log(a)
// 结果: 31

3.3 Reflect.defineProperty()

要创建或编辑对象上的属性,可以使用 Reflect.defineProperty() 方法。它返回一个布尔值,指示属性是否已成功定义。该方法有三个参数:

  • target:目标对象
  • propertyKey:要定义或修改的属性的名称
  • attributes:要定义或修改的属性的描述
  • 「返回值:」 Boolean 值指示了属性是否被成功定义

让我们看看下面的例子:

const obj = {}
Reflect.defineProperty(obj, 'prop', {value: 70})
console.log(obj.prop)
// 结果: 70

Reflect.defineProperty() 方法允许精确添加或修改对象上的属性。更多的细节请参阅类似 Object.defineProperty 。

3.4 Reflect.get()

顾名思义,Reflect.get() 用于从对象检索属性。它接受三个参数:

  • target:需要取值的目标对象
  • propertyKey:需要获取的值的键值
  • receiver:如果 target 对象中指定了 getterreceiver 则为 getter 调用时的 this
  • 「返回值:」 属性的值

让我们看看下面的例子:

const b = [10,11,12,13,14]
console.log(Reflect.get(b, 2))
// 结果: 12
const obj = {name: "Pascal", age: 23}
console.log(Reflect.get(obj, 'age'))
// 结果: 23

3.5 Reflect.getPrototypeOf()

Reflect.getPrototypeOf() 函数返回所提供目标的原型,很像 Object.getPrototypeOf() 。该方法只接受一个参数:

  • target:获取原型的目标对象
  • 「返回值:」 给定对象的原型。如果给定对象没有继承的属性,则返回 null

让我们看看下面的例子:

const profile = {  
  name: 'Pascal'  
};  
const pro = Reflect.getPrototypeOf(profile);  
console.log(pro);

3.6 Reflect.set()

Reflect.set() 方法用于为对象属性赋值。它返回 true,表示属性已成功设置。这个函数有四个参数:

  • target:设置属性的目标对象
  • propertyKey:设置的属性的名称
  • value:设置的值
  • receiver:如果遇到 setterreceiver 则为 setter 调用时的 this
  • 「返回值:」 返回一个 Boolean 值表明是否成功设置属性

让我们看看下面的例子:

const arr1 = [];
Reflect.set(arr1, 0, 'first');
Reflect.set(arr1, 1, 'second');
Reflect.set(arr1, 2, 'third');
console.log(arr1);
// 结果:['first', 'second', 'third']

3.7 Reflect.deleteProperty()

Reflect.deleteProperty() 是一个从对象中删除属性的方法。如果该属性被正确删除,则返回 true。这个函数有两个参数:

  • target:删除属性的目标对象
  • propertyKey:需要删除的属性的名称
  • 「返回值:」 Boolean 值表明该属性是否被成功删除

让我们看看下面的例子:

var obj = { x: 1, y: 2 };
Reflect.deleteProperty(obj, "x"); // true
obj; // { y: 2 }
var arr = [1, 2, 3, 4, 5];
Reflect.deleteProperty(arr, "3"); // true
arr; // [1, 2, 3, , 5]
// 如果属性不存在,返回 true
Reflect.deleteProperty({}, "foo"); // true
// 如果属性不可配置,返回 false
Reflect.deleteProperty(Object.freeze({foo: 1}), "foo"); // false

3.8 Reflect.isExtensible()

Object.isExtensible() 一样,Reflect.isExtensible() 是一个检测对象是否可扩展的方法(例如,是否可以向其添加其他属性)。Reflect.isExtensible() 返回一个布尔值来指示目标是否可扩展。它只考虑一个参数:

  • target:检查是否可扩展的目标对象
  • 「返回值:」 返回一个 Boolean 值表明该对象是否可扩展

让我们看看下面的例子:

const user = {
  name: "xiaan"
};
console.log(Reflect.isExtensible(user))  
// true
Reflect.preventExtensions(user);
console.log(Reflect.isExtensible(user))  
// false

3.9 Reflect.ownKeys()

Reflect.ownKeys() 方法基本上返回一个包含目标对象的属性键的数组。它只考虑一个参数:

  • target:获取自身属性键的目标对象
  • 「返回值:」 由目标对象的自身属性键组成的 Array

让我们看看下面的例子:

const obj = {
  name: "xiaan",
  age: 21
};
const array1 = [];
console.log(Reflect.ownKeys(obj));
// ["name", "age"]
console.log(Reflect.ownKeys(array1));
// ["length"]

3.10 Reflect.getOwnPropertyDescriptor()

Reflect.getOwnPropertyDescriptor() 方法返回一个描述符,它定义了给定对象上的特定属性是如何配置的。它需要两个参数:

  • target:需要寻找属性的目标对象
  • propertyKey:获取自己的属性描述符的属性的名称
  • 「返回值:」 如果属性存在于给定的目标对象中,则返回属性描述符;否则,返回 undefined

让我们看看下面的例子:

const obj = {
  name: "xiaan",
  age: 21
};
console.log(Reflect.getOwnPropertyDescriptor(obj, 'name').value);
// "xiaan"
console.log(Reflect.getOwnPropertyDescriptor(obj, 'age'));
// {value: 21, writable: true, enumerable: true, configurable: true}
console.log(Reflect.getOwnPropertyDescriptor(obj, 'age').writable);
// true

属性描述符可以包含以下属性:

  • value:与属性相关联的值
  • writable:一个布尔值,仅当属性的相关值可修改时返回 true
  • configurable:一个布尔值,仅当属性描述符的类型可以修改且属性可以从相关对象中删除时返回 true
  • enumerable:一个布尔值,仅当属性在相关对象的属性枚举过程中出现时返回 true

3.11 Reflect.has()

Reflect.has() 方法验证是否在目标对象中定义了属性。它返回一个布尔值。Reflect.has() 执行与 in 操作符类似的操作,并接受两个形参:

  • target:目标对象
  • propertyKey:属性名,需要检查目标对象是否存在此属性
  • 「返回值:」 一个 Boolean 类型的对象指示是否存在此属性

让我们看看下面的例子:

const obj = {
  name: "xiaan"
};
console.log(Reflect.has(obj, 'name'));
// true
console.log(Reflect.has(obj, 'age'));
// false
console.log(Reflect.has(obj, 'toString'));
// true

4. 小结

在本文中,我们研究了 JavaScript Reflect 对象,并讨论了 ProxyReflect 之间的区别。我们还研究了如何使用各种 Reflect 方法的示例,包括用于返回对象属性值的 Reflect.get()、用于删除对象属性的 Reflect. deleteProperty() 和用于返回对象属性键的 Reflect. ownKeys()

相关文章
|
2月前
|
缓存 JavaScript 前端开发
深入浅出:使用Node.js构建RESTful API
【9月更文挑战第3天】在数字化浪潮中,后端开发如同搭建一座连接用户与数据的桥梁。本文将带领读者从零开始,一步步用Node.js搭建一个功能完备的RESTful API。我们将探索如何设计API的结构、处理HTTP请求以及实现数据的CRUD操作,最终通过一个简单的实例,展示如何在真实世界中应用这些知识。无论你是初学者还是有一定经验的开发者,这篇文章都会为你揭示后端开发的奥秘,让你轻松入门并掌握这一技能。
93 3
|
2天前
|
JSON JavaScript API
深入浅出Node.js:从零开始构建RESTful API
【10月更文挑战第39天】 在数字化时代的浪潮中,API(应用程序编程接口)已成为连接不同软件应用的桥梁。本文将带领读者从零基础出发,逐步深入Node.js的世界,最终实现一个功能完备的RESTful API。通过实践,我们将探索如何利用Node.js的异步特性和强大的生态系统来构建高效、可扩展的服务。准备好迎接代码和概念的碰撞,一起解锁后端开发的新篇章。
|
12天前
|
JavaScript 中间件 API
Node.js进阶:Koa框架下的RESTful API设计与实现
【10月更文挑战第28天】本文介绍了如何在Koa框架下设计与实现RESTful API。首先概述了Koa框架的特点,接着讲解了RESTful API的设计原则,包括无状态和统一接口。最后,通过一个简单的博客系统示例,详细展示了如何使用Koa和koa-router实现常见的CRUD操作,包括获取、创建、更新和删除文章。
34 4
|
5天前
|
JavaScript 前端开发 NoSQL
深入浅出:使用Node.js构建RESTful API
【10月更文挑战第35天】在数字时代的浪潮中,后端技术如同海洋中稳固的灯塔,为前端应用提供数据和逻辑支撑。本文旨在通过浅显易懂的方式,带领读者了解如何利用Node.js这一强大的后端平台,搭建一个高效、可靠的RESTful API。我们将从基础概念入手,逐步深入到代码实践,最终实现一个简单的API示例。这不仅是对技术的探索,也是对知识传递方式的一次创新尝试。让我们一起启航,探索Node.js的奥秘,解锁后端开发的无限可能。
|
1月前
|
JavaScript 前端开发 API
探索Vue.js 3的组合式API:一种更灵活的组件状态管理方式
【10月更文挑战第5天】探索Vue.js 3的组合式API:一种更灵活的组件状态管理方式
|
1月前
|
JSON JavaScript 前端开发
使用 Node.js 和 Express 构建 RESTful API 服务器
【10月更文挑战第3天】使用 Node.js 和 Express 构建 RESTful API 服务器
|
28天前
|
JSON JavaScript 前端开发
使用JavaScript和Node.js构建简单的RESTful API服务器
【10月更文挑战第12天】使用JavaScript和Node.js构建简单的RESTful API服务器
16 0
|
1月前
|
JSON JavaScript API
Node.js RESTful API
10月更文挑战第8天
13 0
|
1月前
|
JSON JavaScript 前端开发
使用 Node.js 和 Express 构建 RESTful API
【10月更文挑战第3天】 使用 Node.js 和 Express 构建 RESTful API
|
1月前
|
Web App开发 JSON JavaScript
使用 Node.js 构建一个简单的 RESTful API
【10月更文挑战第3天】使用 Node.js 构建一个简单的 RESTful API