前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >深入浅出 JavaScript Reflect API

深入浅出 JavaScript Reflect API

作者头像
用户8921923
发布2022-10-24 19:19:06
3370
发布2022-10-24 19:19:06
举报
文章被收录于专栏:全栈私房菜全栈私房菜

深入浅出 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:将拦截目标操作的代理配置

这里有一个例子:

代码语言:javascript
复制
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 为其初始化参数的对象实例。

考虑下面的例子:

代码语言:javascript
复制
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()

代码语言:javascript
复制
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 指定了)。

代码语言:javascript
复制
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 值的给定的函数后返回的结果

让我们看看下面的例子:

代码语言:javascript
复制
const arr = [3,5,20,3,31]
const a = Reflect.apply(Math.max, undefined, arr)
console.log(a)

// 结果: 31

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

代码语言:javascript
复制
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 值指示了属性是否被成功定义

让我们看看下面的例子:

代码语言:javascript
复制
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
  • 「返回值:」 属性的值

让我们看看下面的例子:

代码语言:javascript
复制
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

让我们看看下面的例子:

代码语言:javascript
复制
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 值表明是否成功设置属性

让我们看看下面的例子:

代码语言:javascript
复制
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 值表明该属性是否被成功删除

让我们看看下面的例子:

代码语言:javascript
复制
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 值表明该对象是否可扩展

让我们看看下面的例子:

代码语言:javascript
复制
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

让我们看看下面的例子:

代码语言:javascript
复制
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

让我们看看下面的例子:

代码语言:javascript
复制
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 类型的对象指示是否存在此属性

让我们看看下面的例子:

代码语言:javascript
复制
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()

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2022-10-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 全栈私房菜 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 深入浅出 JavaScript Reflect API
    • 1. 什么是 JavaScript Reflect?
      • 2. Proxy 和 Reflect 之间的区别?
        • 3. 使用 JavaScript Reflect API 的方法
          • 3.1 Reflect.construct()
          • 3.2 Reflect.apply()
          • 3.3 Reflect.defineProperty()
          • 3.4 Reflect.get()
          • 3.5 Reflect.getPrototypeOf()
          • 3.6 Reflect.set()
          • 3.7 Reflect.deleteProperty()
          • 3.8 Reflect.isExtensible()
          • 3.9 Reflect.ownKeys()
          • 3.10 Reflect.getOwnPropertyDescriptor()
          • 3.11 Reflect.has()
        • 4. 小结
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档