當涉及計算機編程環境中的反射時,其定義為在運行時檢查,自省和修改其自身的結構和行為的能力(定義來自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。
熱門源碼