Metaprogramming is an advanced concept that provides the ability to extend a program at runtime. It is used extensively by libraries and frameworks, but you can also cautiously use it to extend third-party classes in order to make code fluent, less noisy, and easier to use. Member injection is useful to add a known method, field, or property into a class without inheriting from it. To add a method to a class, inject it into the class’s prototype. To inject properties, use the defineProperty() or defineProperties() method.
The following exercises will help you strengthen your metaprogramming skills to query objects and inject members. You can find answers to these exerciseshere.
Complete the following code to print the properties of the given object.
| 'use strict'; |
| |
| const printProperties = function(obj) { |
| //Your code goes here |
| }; |
| |
| printProperties({language: 'JavaScript', typing: 'dynamic'}); |
| printProperties( |
| {tool: 'Redux', language: 'JavaScript', purpose: 'transpiler', }); |
| |
| /* |
| language is JavaScript |
| typing is dynamic |
| tool is Redux |
| language is JavaScript |
| purpose is transpiler |
| */ |
Implement a percent() method to produce the desired result shown in the following code.
| 'use strict'; |
| |
| //Your code goes here |
| |
| const value1 = 0.35; |
| const value2 = 0.91; |
| |
| console.log(value1.percent()); //35% ` |
| console.log(value2.percent()); //91% ` |
| |
| try { |
| const value3 = 44; |
| console.log(value3.percent()); |
| } catch(ex) { |
| console.log(ex.message); // value should be less than 1 |
| } |
In the following code, create custom properties to extract the integer part and the fractional part from a number.
| 'use strict'; |
| |
| //Your code goes here |
| |
| const printParts = function(number) { |
| console.log( |
| `whole: ${number.integerPart} decimal: ${number.fractionalPart}`); |
| }; |
| |
| printParts(22.12); //whole: 22 decimal: 12 |
| printParts(.14); //whole: 0 decimal: 14 |
| printParts(-23.19); //whole: -23 decimal: 19 |
| printParts(42); //whole: 42 decimal: 0 |
Let’s enhance the Set class with a combine() instance method.
| 'use strict'; |
| |
| //Your code goes here |
| |
| const names1 = new Set(['Tom', 'Sara', 'Brad', 'Kim']); |
| const names2 = new Set(['Mike', 'Kate']); |
| |
| const combinedNames = names1.combine(names2); |
| |
| console.log(names1.size); //4 |
| console.log(names2.size); //2 |
| console.log(combinedNames.size); //6 |
| console.log(combinedNames); |
| //Set { 'Tom', 'Sara', 'Brad', 'Kim', 'Mike', 'Kate' } |
How would you add a method to an instance instead of to all the instances of a class? When would you prefer doing that instead of adding the method so it is available on all instances of a class?