当涉及计算机编程环境中的反射时,其定义为在运行时检查,自省和修改其自身的结构和行为的能力(定义来自Wikipedia页面)。此外,它对于元编程是众所周知的。因此,您可以在运行时操作对象的变量,属性和方法。使用JavaScript语言,可以进行反思。但是,在过去,它的限制和反射方法并不直接适用于许多开发人员。但是,如今,情况已不再如此,该Reflect对象提供了更好的有意义的方法来帮助开发人员轻松进行反射编程。因此,我们将要解决并观察Reflect物体可以为我们提供什么,特别是它的static方法。好,那就开始吧。
以下是有关ReflectAPI的注意事项。
它使用的Reflect是全局和静态对象,因此,您无法创建该对象的实例。同样,其所有方法均为static。
它提供了运行时级别的检查和操作对象属性的功能,也称为元编程。此外,在ES6之前,JavaScript语言确实提供了对象反射API,但是它们并不是真正组织起来的,并且在失败时会引发异常。因此,今天,ReflectAPI在Reflect对象的帮助下改善了我们进行元/反射编程的方式。
此方法使用指定的参数调用要调用的目标函数。换句话说,如果您要调用某个函数而不真正直接调用它,而是要使用此方法来调用目标函数。
此方法采用三个参数:
请参阅以下示例:
/** start of Reflect.apply() */ //let's define a function function getSum(num1, num2) { return `${this.value}${num1 + num2}`; } //let's try to invoke the function using Reflect.apply() const returnedValueOfFunc = Reflect.apply(getSum, { value:'Sum of 1 and 2 is '}, [ 1, 2]); console.log(returnedValueOfFunc); //output: Sum of 1 and 2 is 3 /** end of Reflect.apply() */
此方法用于调用构造函数。换句话说,此方法返回由目标构造函数创建的新实例。
此方法采用三个参数:
请参阅以下示例:
/** start of Reflect.constructor */ //let's define a constructor function function Customer(title,firstName, lastName) { this.title = title; this.firstName = firstName; this.lastName = lastName; this.showFullName = function () { return `${this.title}. ${lastName}, ${firstName} is from the ${this.country}`; } } //let's define another constructor set the prototype to add a new property. function Employee() { } Employee.prototype.country = 'Philippines'; const myCustomer = Reflect.construct(Customer, ['Dr','Jin Vincent', 'Necesario'],Employee); console.log(myCustomer.showFullName()); //output: Dr. Necesario, //Jin Vincent is from the Philippines /** end of Reflect.constructor */
可能您会猜测此方法用于定义对象的新属性或更新现有属性。如果这就是您的想法,那么您猜对了。
此方法采用三个参数:
而且,它具有的等效方法是Object.defineProperty()。现在我们已经意识到了这一点,您可能会想:“有什么区别?” ,我将在下一部分中回答。之后,我们将进入代码示例。
基本上,这些方法执行相同的操作,但主要区别在于这些方法返回的值。现在的区别是该Reflect.defineProperty()方法返回一个Boolean,而该Object.defineProperty()返回了修改后的对象。此外,如果方法Object.defineProperty()失败,则当Reflect.defineProperty()方法返回false结果时它将引发异常。
在进入代码示例之前,让我们尝试了解该方法的第三个参数Reflect.defineProperty()。在任何面向对象的语言中,每个对象属性都是数据属性或访问器属性。
基本上,数据属性的值可以是可读或不可读或可写的,而访问器属性具有一对用于设置和检索该属性值的getter-setter函数。
在深入研究代码之前,我们首先来看一下描述符对象的属性:
让我们来看一个代码示例,用于将属性定义为可写,可配置和可枚举。
/** start of Reflect.defineProperty */ const book = {}; //let's define a property that is writable, configurable and enumerable Reflect.defineProperty(book, "title", { value: "JavaScript For Kids", writable: true, configurable: true, enumerable:true }); //let's check the book object console.log(book); //output: {title: "JavaScript For Kids"} //let's check the title of the book console.log(book.title); //output: JavaScript For Kids //let's change the value of the Book property, //this is possible because writable is set to true book.title = "Beginning Node.js"; //let's check the title of the book console.log(book.title); //output: Beginning Node.js //let's check if we can enumerate the title property for (const key in book) { console.log(key); //output: title } /** end of Reflect.defineProperty */
将属性定义为不可写,不可配置和不可枚举的另一个示例。
/** start of Reflect.defineProperty */ const laptop = {}; //let's define a property that isn't writable, configurable and enumerable Reflect.defineProperty(laptop, "brand", { value: "IBM", writable: false, configurable: false, enumerable: false }); //let's check the laptop object console.log(laptop); //output: {brand: "IBM"} //let's check the brand of the laptop console.log(laptop.brand); //output: IBM //let's change the value of the brand property, //this is not possible because writable is set to false laptop.brand = "DELL"; //let's check the brand of the laptop console.log(laptop.brand); //output: IBM //let's check if we can enumerate the brand property for (const key in laptop) { console.log(key); //output: n/a } /** end of Reflect.defineProperty */
同样,在深入研究代码示例之前,让我们看一下访问器属性描述符属性:
让我们看下面的代码示例:
/** start of accessor property */ /** start of Reflect.defineProperty */ const laundryShop = { __defaultName__: "Queens Care Laundry Shop" } Reflect.defineProperty(laundryShop, "businessName", { get: function () { return this.__defaultName__; }, set: function (value){ this.__defaultName__ = value; }, configurable: true, enumerable: true }); console.log(laundryShop); //output: {__defaultName__: "Queens Care Laundry Shop"} console.log(laundryShop.businessName); //output: Queens Care Laundry Shop laundryShop.businessName = "Laundry Shop"; console.log(laundryShop.businessName); //output: Laundry Shop /** end of accessor property */ /** end of Reflect.defineProperty */
方法本身的名称描述了它的作用。它基本上删除了对象的属性。
此方法有两个参数:
让我们看下面的代码示例:
// /** start of Reflect.deleteProperty */ let car = { model: "Toyota Hilux", yearModel: 2020 }; //let us see the object before removing the model property. console.log(car); //output: {model: "Toyota Hilux", yearModel: 2020} Reflect.deleteProperty(car, "model"); //let use the object after the removal of the model property. console.log(car); //output: { yearModel: 2020 } /** end of Reflect.deleteProperty */
此方法用于设置对象属性的值。
此方法采用三个参数:
让我们看下面的代码示例:
/** Start of Reflect.set */ const computer2 = { processor: "Intel", brand: "Dell", operatingSystem: "windows 7" }; console.log(computer2); //output: {processor: "Intel", brand: "Dell", operatingSystem: "windows 7"} Reflect.set(computer2, "processor", "AMD"); console.log(computer2); //output: {processor: "AMD", brand: "Dell", operatingSystem: "windows 7"} // /** end of Reflect.set */
显然,此方法与完全相反Reflect.set()。此方法用于检索对象属性的值。
此方法采用三个参数:
让我们看下面的代码示例:
/** Start of Reflect.get */ var computer1 = { processor: "Intel", brand: "Dell", operatingSystem: "windows 7" }; console.log(computer1); Reflect.get(computer1, "processor"); console.log(computer1.processor); /** end of Reflect.get */
注意:如果该属性是访问器属性,那么我们可以提供可选的第三个参数,它将是函数this内部的get值。
让我们看下面的代码示例:
/** start of Reflect.get with 3rd argument */ const dinoComputer = { processor: "Intel", brand: "Dell", operatingSystem: "windows 7" }; Reflect.defineProperty(dinoComputer, "computerDetails", { get: function() { return new String().concat(`*********Computer Details********\r\n`, `****Processor: ${this.processor}***********\r\n`, `****Brand: ${this.brand}*****************\r\n`, `****Operating System: ${this.operatingSystem}*\r\n`); } }); console.log(dinoComputer); let oldComputer = Reflect.get(dinoComputer, "computerDetails", { processor: "AMD K62", brand: "Clone", operatingSystem: "Windows XP" }); console.log(oldComputer); /** end of Reflect.get with 3rd argument */
输出:
此方法用于检索对象属性的描述符。Kinda易于实现。
此方法有两个参数:
让我们看下面的代码示例:
/** start of Reflect.getOwnPropertyDescriptor */ const myDog = { yourPet: true, name: "Bruno" } const descriptor = Reflect.getOwnPropertyDescriptor(myDog, "name"); console.log(descriptor.value); //output: Bruno console.log(descriptor.writable); //output: true console.log(descriptor.enumerable);//output: true console.log(descriptor.configurable); //output: true /** end of Reflect.getOwnPropertyDescriptor */
此方法用于检索对象的内部原型,即对象的内部属性的值。此方法只有一个参数,即目标/引用对象。
需要注意的一点是,它与Object.getPrototypeOf()方法相同。
让我们看下面的代码示例:
/** start of Reflect.getPrototypeOf*/ const product = { __proto__: { category: { id: "1", name: "Electronics", description: "Electronic devices" } } } const myCategoryResult = Reflect.getPrototypeOf(product); console.log(myCategoryResult.category); //output: { id: "1", name: "Electronics", description: "Electronic devices" } /** end of Reflect.getPrototypeOf */
此方法用于设置对象的内部prototype(__proto__)属性值。
此方法有两个参数:
让我们看下面的代码示例:
/**start of Reflect.setPrototypeOf */ const anime = { popularAnimeShow: "Voltes V" } Reflect.setPrototypeOf(anime, { fullName: "Super Electromagnetic Machine Voltes V" }); console.log(anime.__proto__.fullName); //output: Super Electromagnetic Machine Voltes V /** end of Reflect.setPrototypeOf */
此方法用于检查对象中是否存在属性。true如果属性存在,则返回,否则返回false。
此方法有两个参数:
让我们看下面的代码示例:
/** start of Reflect.has */ const band = { name: "EHeads", songs: ['Ang Huling El Bimbo', 'With A Smile'] } console.log(Reflect.has(band, "name")); //output: true console.log(Reflect.has(band, "songs")); //output: true console.log(Reflect.has(band, "producer")); //output: false /** end of Reflect.has */
此方法用于检查对象是否可扩展。换句话说,如果我们可以向对象添加新属性。此方法只有一个参数,即目标/引用对象。
让我们看下面的代码示例:
/** start of Reflect.isExtensible */ const problem = { problemIs: "I'm in love with a college girl" } console.log(Reflect.isExtensible(problem)); //output: true Reflect.preventExtensions(problem); //let's prevent this object to be extended. //This is the same as Object.preventExtensions(problem); console.log(Reflect.isExtensible(problem)); //output: false /** end of Reflect.isExtensible */ /** start of Reflect.preventExtensions */
要知道,我们还可以通过以下方法将对象标记为不可扩展:
此方法用于将对象标记为不可扩展。它返回一个Boolean,指示是否成功。此方法只有一个参数,即目标/引用对象。
让我们看下面的代码示例:
/** start of Reflect.preventExtensions */ const song = { title: "Magasin", band: "EHeads" } console.log(Reflect.isExtensible(song)); //output: true Reflect.preventExtensions(song); //This is the same as Object.preventExtensions(song); console.log(Reflect.isExtensible(song)); //output: false /** end of Reflect.preventExtensions */
此方法返回对象的键属性的数组。但是,它忽略了继承的属性(__proto__)。此方法只有一个参数,即目标/引用对象。
让我们看下面的代码示例:
/** start of Reflect.ownKeys */ const currency = { name: "USD", symbol: "$", globalCurrency: true, __proto__: { country: "USA" } } const keys = Reflect.ownKeys(currency); console.log(keys); //output: ["name", "symbol", "globalCurrency"] console.log(keys.length);//output: 3 /** Output: * name symbol globalCurrency */ keys.forEach(element => { console.log(element); }); /** end of Reflect.ownKeys */
在本文中,我们学习了使用该Reflect对象的JavaScript反射API 。不仅如此,我们还解决了Reflect对象必须提供的大多数方法,并且已经了解了如何在特定的场景中以不同的方式实现它。总体而言,这篇文章介绍了JavaScript ReflectAPI。
热门源码