JavaScript 反射

摘要: 本教程将介绍 JavaScript 反射和 ES6 中的 Reflect API。

什么是反射

在计算机编程中,反射是指程序在运行时能够操作变量、属性和对象的方法。

在 ES6 之前,JavaScript 已经具备反射功能,尽管这些功能当时并未被社区或规范正式称为“反射”。例如,Object.keys()Object.getOwnPropertyDescriptor()Array.isArray() 等方法就是经典的反射功能。

ES6 引入了一个新的全局对象,名为 Reflect,它允许您调用方法、构造对象、获取和设置属性,以及操作和扩展属性。

Reflect API 非常重要,因为它允许您开发能够处理动态代码的程序和框架。

Reflect API

与大多数全局对象不同,Reflect 不是构造函数。这意味着您不能使用 new 运算符与 Reflect 一起使用,也不能将 Reflect 作为函数调用。它类似于 MathJSON 对象。Reflect 对象的所有方法都是静态的。

  • Reflect.apply() – 使用指定的参数调用函数
  • Reflect.construct() – 类似于 new 运算符,但它是一个函数。它等效于调用 new target(...args)
  • Reflect.defineProperty() – 类似于 Object.defineProperty(),但返回一个布尔值,指示该属性是否成功定义在对象上。
  • Reflect.deleteProperty() – 类似于 delete 运算符,但它是一个函数。它等效于调用 delete objectName[propertyName]
  • Reflect.get() – 返回属性的值。
  • Reflect.getOwnPropertyDescriptor() – 类似于 Object.getOwnPropertyDescriptor()。如果该属性存在于对象上,它会返回该属性的属性描述符,否则返回 undefined
  • Reflect.getPrototypeOf() – 与 Object.getPrototypeOf() 相同。
  • Reflect.has() – 类似于 in 运算符,但它是一个函数。它返回一个布尔值,指示该属性(无论是自身所有还是继承的)是否存在。
    Reflect.isExtensible() – 与 Object.isExtensible() 相同。
  • Reflect.ownKeys() – 返回对象自身所有属性的键(不包括继承的属性)的数组。
  • Reflect.preventExtensions() – 类似于 Object.preventExtensions()。它返回一个布尔值。
  • Reflect.set() – 将值分配给属性,并返回一个布尔值,如果属性成功设置,则返回 true。
  • Reflect.setPrototypeOf() – 设置对象的原型

让我们来看一些使用 Reflect API 的示例

创建对象: Reflect.construct()

Reflect.construct() 方法类似于 new 运算符,但它是一个函数。它等效于调用 new target(...args),并且可以指定不同的原型。

Reflect.construct(target, args [, newTarget])
Code language: CSS (css)

Reflect.construct() 返回 target 的新实例,或者如果指定了 newTarget,则返回 newTarget,由 target 作为构造函数使用给定的类似数组的对象 args 初始化。请参见以下示例

class Person {
    constructor(firstName, lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }
    get fullName() {
        return `${this.firstName} ${this.lastName}`;
    }
};

let args = ['John', 'Doe'];

let john = Reflect.construct(
    Person,
    args
);

console.log(john instanceof Person);
console.log(john.fullName); // John Doe
Code language: JavaScript (javascript)

输出

true
John Doe
Code language: JavaScript (javascript)

在本例中

  • 首先,定义一个名为 Person 的类。
  • 其次,声明一个包含两个字符串的 args 数组。
  • 第三,使用 Reflect.construct() 方法创建一个 Person 类的实例。john 对象是 Person 类的实例,因此它具有 fullName 属性。

调用函数: Reflect.apply()

在 ES6 之前,您可以使用 Function.prototype.apply() 方法来调用具有指定 this 值和 arguments 的函数。例如

let result = Function.prototype.apply.call(Math.max, Math, [10, 20, 30]);
console.log(result);
Code language: JavaScript (javascript)

输出

30

此语法非常冗长。

Reflect.apply() 提供与 Function.prototype.apply() 相同的功能,但更简洁易懂

let result = Reflect.apply(Math.max, Math, [10, 20, 30]);
console.log(result);
Code language: JavaScript (javascript)

以下是 Reflect.apply() 方法的语法

Reflect.apply(target, thisArg, args)
Code language: JavaScript (javascript)

定义属性: Reflect.defineProperty()

Reflect.defineProperty() 类似于 Object.defineProperty()。但是,它返回一个布尔值,指示属性是否成功定义,而不是抛出异常

Reflect.defineProperty(target, propertyName, propertyDescriptor)
Code language: JavaScript (javascript)

请参见以下示例

let person = {
    name: 'John Doe'
};

if (Reflect.defineProperty(person, 'age', {
        writable: true,
        configurable: true,
        enumerable: false,
        value: 25,
    })) {
    console.log(person.age);
} else {
    console.log('Cannot define the age property on the person object.');

}Code language: JavaScript (javascript)

在本教程中,您学习了 JavaScript 反射和 Reflect API,它包含许多反射方法。

本教程对您有帮助吗?