1, What's the use of Reflect?
In a word, reflection is of no use. It doesn't have any force except that it makes people look tall.
To be exact, Reflect is more like a syntax variant. All methods linked to it can find the corresponding original syntax, that is, Reflect is very replaceable.
In fact, from the literal meaning of the word Reflect, we can understand the charm of Reflect. The Chinese meaning of Reflect is "reflection". The sunlight is reflected on the mirror. In fact, photons are still those photons, but the direction has changed.
For example:
The reflection object mounts many static methods. The so-called static methods are and math Round () so that you can use the method directly without new.
The two commonly used methods are get() and set():
Reflect.get(target, propertyKey[, receiver]) Reflect.set(target, propertyKey, value[, receiver])
In terms of function, it is equivalent to:
target[propertyKey] target[propertyKey] = value;
For example, there is an input box on the page, and its DOM object variable is input. Usually, most of the statements we use to assign values to the whole input box are:
input.value = 'zhangxinxu';
You can directly use reflect Set() method instead:
Reflect.set(input, 'value', 'zhangxinxu')
The effect is as like as two peas.
For another example, we want to redefine the value attribute of input so that when the value attribute of the input box changes, the 'change' event can be triggered at the same time. Here is the familiar object Schematic diagram of defineproperty() method implementation:
const props = Object.getOwnPropertyDescriptor(input, 'value'); Object.defineProperty(input, 'value', { ...props, set (v) { let oldv = this.value; props.set.call(this, v); // Manually trigger the change event if (oldv !== v) { this.dispatchEvent(new CustomEvent('change')); } } });
For relevant introduction, please refer to this article:“ Implementation of js change event triggered by value attribute assignment of input box"
The above code can be implemented by using the Reflect object. The specific JavaScript code is as follows.
const props = Reflect.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value'); Reflect.defineProperty(input, 'value', { ...props, set (v) { let oldv = this.value; props.set.call(this, v); // Manually trigger the change event if (oldv !== v) { this.dispatchEvent(new CustomEvent('change')); } } });
We can test that the HTML of the page is as follows:
<input id="input">
The test code is:
input.addEventListener('change', () => { document.body.append('Change~'); }); input.value = 'zhangxinxu';
At this time, you can see the text "changed ~" on the page, and the screenshot is as follows:
You can experience it at this JSBIN address: https://output.jsbin.com/vugucajepa
2, Nuance - return value
There must be a reason for the existence of things. If Reflect just changes the syntax, the meaning of existence is not great. Obviously, there must be other considerations for the emergence of Reflect objects.
One of the things that I think makes sense is the return value.
Assignment is not always successful for an object.
For example, we set the type attribute of {input} to read-only, as follows:
Object.defineProperty(input, 'type', { get () { return this.getAttribute('type') || 'text'; } });
The traditional attribute assignment using the equal sign does not know whether the final execution is successful, which needs further detection by the developer.
For example:
console.log(input.type = 'number'); // Output false console.log(Reflect.set(input, 'type', 'number'));
The return value of the assignment in the above line is' number '. It is unknown whether it is successful to change the value of the type attribute of the input box.
But the following line of statements uses reflect Set () method, you can know whether the setting is successful, because reflect The return value of set () is true or false (as long as the parameter type is accurate).
In addition to knowing the execution results, the Reflect method also has the advantage that it will not interrupt the normal code logic execution due to an error.
For example, the following code:
(function () { 'use strict'; var frozen = { 1: 81 }; Object.freeze(frozen); frozen[1] = 'zhangxinxu'; console.log('no log'); })();
The following TypeError error occurs:
Uncaught TypeError: Cannot assign to read only property '1' of object '#<Object>'
The following statement console Log ('No log ') is not executed.
However, if the Reflect method is used, the console statement can be executed, for example:
(function () { 'use strict'; var frozen = { 1: 81 }; Object.freeze(frozen); Reflect.set(frozen, '1', 'zhangxinxu'); console.log('no log'); })();
The log output value after the console runs is shown in the following figure:
3, receiver parameter in set and get methods
In terms of functionality, reflect Get() and reflect There is no difference between the set () method and the direct object assignment. They can replace each other. For example, the JS effects of the following two paragraphs are the same.
Still use the DOM element input to indicate.
One may wonder, why not use pure object gestures?
Because I find that most front ends are not very interested in DOM, I will do the opposite and deliberately respond to people; Another reason is that DOM objects are more concrete and what you see is what you get, which is suitable for perceptual students.
const xyInput = new Proxy(input, { set (target, prop, value) { if (prop == 'value') { target.dispatchEvent(new CustomEvent('change')); } target[prop] = value; return true; }, get (target, prop) { return target[prop]; } }); input.addEventListener('change', () => { document.body.append('Change~'); }); xyInput.value = 'zhangxinxu'; And below JS The code effect is similar. const xyInput = new Proxy(input, { set (target, prop, value) { if (prop == 'value') { target.dispatchEvent(new CustomEvent('change')); } return Reflect.set(target, prop, value); }, get (target, prop) { return Reflect.get(target, prop); } }); input.addEventListener('change', () => { document.body.append('Change~'); }); xyInput.value = 'zhangxinxu';
All have the effects shown in the figure below:
However, when the optional parameter receiver parameter needs to be used, there will be a difference between direct object assignment and reflection assignment.
First, for DOM elements, an error will be reported when the receiver parameter is applied.
For example, the following JS will report an error:
Reflect.set(input, 'value', 'xxx', new Proxy({}, {}));
Uncaught TypeError: Illegal invocation
However, there will be no problem if the input is replaced with an ordinary pure object, for example:
// It can be executed normally Reflect.set({}, 'value', 'xxx', new Proxy({}, {}));
About receiver parameters
After all, what exactly is the receiver parameter used for?
Receiver means the receiver, which means the body object that calls the corresponding property or method. Generally, the receiver parameter does not need to be used. However, if inheritance occurs, the receiver parameter needs to be used to clarify the calling body.
For example, the following example:
let miaoMiao = { _name: 'vaccines', get name () { return this._name; } } let miaoXy = new Proxy(miaoMiao, { get (target, prop, receiver) { return target[prop]; } }); let kexingMiao = { __proto__: miaoXy, _name: 'Kexing vaccine' }; // The result is a vaccine console.log(kexingMiao.name);
In fact, the expected display here should be "Kexing vaccine", not "vaccine".
At this time, you need to use the receiver parameter. See the red line below for code changes:
let miaoMiao = { _name: 'vaccines', get name () { return this._name; } } let miaoXy = new Proxy(miaoMiao, { get (target, prop, receiver) { return Reflect.get(target, prop, receiver); // It can also be abbreviated as reflect get(...arguments) } }); let kexingMiao = { __proto__: miaoXy, _name: 'Kexing vaccine' }; // The result is Kexing vaccine console.log(kexingMiao.name);
At this time, the operation result is the expected "Kexing vaccine", as shown in the screenshot below:
This is the function of the receiver parameter. The calling object can be regarded as the target parameter instead of the object constructed by the original Proxy.
4, Other and concluding remarks
Reflect ion objects are often used with Proxy proxies for three reasons:
- As like as two peas of Proxy, the second static methods provided by Reflect are exactly the same as those of handle. See the following comparative description for details.
- The return value required by Proxy get/set() method is the return value of Reflect's get/set method. It can be used naturally, which is more convenient and accurate than direct object assignment / obtaining value.
- The receiver parameter is irreplaceable.
The following table shows the static methods of Reflect and other corresponding functions or function symbols.
Reflect method | be similar to |
---|---|
Reflect.apply(target, thisArgument, argumentsList) | Function.prototype.apply() |
Reflect.construct(target, argumentsList[, newTarget]) | new target(...args) |
Reflect.defineProperty(target, prop, attributes) | Object.defineProperty() |
Reflect.deleteProperty(target, prop) | delete target[name] |
Reflect.get(target, prop[, receiver]) | target[name] |
Reflect.getOwnPropertyDescriptor(target, prop) | Object.getOwnPropertyDescriptor() |
Reflect.getPrototypeOf(target) | Object.getPrototypeOf() |
Reflect.has(target, prop) | in operator |
Reflect.isExtensible(target) | Object.isExtensible() |
Reflect.ownKeys(target) | Object.keys() |
Reflect.preventExtensions(target) | Object.preventExtensions() |
Reflect.set(target, prop, value[, receiver]) | target[prop] = value |
Reflect.setPrototypeOf(target, prototype) | Object.setPrototypeOf() |
It is the person as his name suggests that Reflect is the "reflection" of other methods and operators.
OK, the above is the content of this article. Let's learn about the 7788 of Reflect.
I hope it can be helpful to everyone's study.
Welcome to forward, welcome to share, thank you!