1. Monitoring object operations
Let's first look at a requirement: there is an object, we want to listen to the process of setting or obtaining properties in this object.
- Can we achieve this through the knowledge we have learned before?
- In fact, it is OK. We can do it by storing the attribute descriptor in the previous attribute descriptor; listen to the object's operations
The code on the left uses the previous onesStore attribute descriptors
To listen for the operation of the attribute.
const obj = { name: "why", age: 18, height: 1.88 } // Requirements: Listen to all operations of object properties// Listen to attribute operations// 1. For a property// let _name = // (obj, "name", { // set: function(newValue) { // ("Listen: Set a new value for name:", newValue)// _name = newValue // }, // get: function() { // ("Listen: Get the value of name")// return _name // } // }) // 2. Listen to all properties: traverse all properties, use defineProperty for each propertyconst keys = (obj) for (const key of keys) { let value = obj[key] (obj, key, { set: function(newValue) { (`monitor: Give${key}Set a new value:`, newValue) value = newValue }, get: function() { (`monitor: Get${key}Value of`) return value } }) } // () // = "kobe" () = 17 ()
But what are the disadvantages of doing this?
- First of all, the original intention of design is not to listen to all attributes in an object.
- When we define certain attributes, our original intention is to define ordinary attributes, but later we forcefully turn them into data attribute descriptors.
- Secondly, if we want to listen for more abundant operations, such as adding new attributes and deleting attributes, then there is nothing we can do.
So we need to knowStore data descriptors
The original intention of design is not to monitor a complete object.
2. Basic use of Proxy
In ES6, a new Proxy class was added. This class can be seen from its name and is used to help us create a proxy:
- That is, if we wish
Listen to an object's related operations
, then we can first create a proxy object (Proxy object); - All operations on the object are then
Completed by proxy object
, the proxy object can listen to what operations we want to perform on the original object;
We can implement the above case with Proxy once:
- First, we need a new Proxy object and pass it in
Objects that need to be listened to
as well asA processing object
, can be calledhandler
;- const p = new Proxy(target, handler)
- Secondly, our subsequent operations are directly on Proxy operations, rather than the original objects, because we need to listen in the handler;
const obj = { name: "why", age: 18, height: 1.88 } // 1. Create a Proxy objectconst objProxy = new Proxy(obj, { set: function(target, key, newValue) { (`monitor: monitor${key}Setting value: `, newValue) target[key] = newValue }, get: function(target, key) { (`monitor: monitor${key}Get`) return target[key] } }) // 2. For all operations of obj, you should operate objProxy// () // = "kobe" // () // = "james" = "Guangzhou City" ()
3. Common Proxy capturers
set and get capturers
If we want to listen for some specific operations, we can add the corresponding one in the handlerCatcher(Trap):
Set and get correspond to function types respectively;
- The set function has four parameters:
- target: target object (listening object);
- property: the property key to be set;
- value: new attribute value;
- receiver: the proxy object to be called;
- The get function has three parameters:
- target: target object (listening object);
- property: the acquired property key;
- receiver: the proxy object to be called;
Other capturers
What do the 13 capturers do?
()
- Method capture.
()
- Method capture.
()
- The method's catcher (judging whether new attributes can be added).
()
- Method capture.
()
- Method capture.
()
- Method capture. Proxy All Captors
()
- Methods and methods capturers.
()
- in operator capturer.
()
- The capturer for the property read operation.
()
- Properties set the capture of the operation.
()
- delete operator capture.
()
- The capturer for function call operations.
- ()
- new operator capturer.
const obj = { name: "why", age: 18, height: 1.88 } // 1. Create a Proxy objectconst objProxy = new Proxy(obj, { set: function(target, key, newValue) { (`monitor: monitor${key}Setting value: `, newValue) target[key] = newValue }, get: function(target, key) { (`monitor: monitor${key}Get`) return target[key] }, deleteProperty: function(target, key) { (`monitor: monitor删除${key}property`) delete }, has: function(target, key) { (`monitor: monitorinjudge ${key}property`) return key in target } }) delete ("age" in objProxy)
construct and apply
Of course, we will also see that there are construct and apply in the capture, which are applied to function objects:
function foo(num1, num2) { (this, num1, num2) } const fooProxy = new Proxy(foo, { apply: function(target, thisArg, otherArgs) { ("The listener performed the apply operation") (thisArg, otherArgs) }, construct: function(target, otherArray) { ("The monitor performed new operation") (target, otherArray) return new target(...otherArray) } }) // ("abc", [111, 222]) new fooProxy("aaa", "bbb")
4. Introduction and function of Reflect
Reflect is also a new API added to ES6, it isAn object
, literally meansreflection。
So what's the use of this Reflect?
- It mainly provides many methods for manipulating JavaScript objects, a bit like the methods for manipulating objects in Object;
- For example (target) is similar to ();
- For example (target, propertyKey, attributes) is similar to ();
If we have an Object that can do these operations, thenWhat do you need to add new objects like Reflect
Woolen cloth?
- This is because this pair was not considered in the early ECMA specifications
The object itself
How to design operations will be more standardized, so put these APIs on Object; - but
Object as a constructor
, these operations are not suitable in fact on it; - Including some
Similar to the in, delete operator
, making JS look a little strange; - So in ES6
Added Reflect
, let us concentrate these operations on the Reflect object; - In addition, when using Proxy, you can do it
Don't operate the original object
;
For the API relationship between Object and Reflect objects, you can refer to the MDN documentation:
/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Reflect/Comparing_Reflect_and_Object_methods
Difference between Object and Reflect: Reflect has a return value
"use strict" const obj = { name: "why", age: 18 } (obj, "name", { configurable: false }) // () // 1. Operation in the previous way// delete // if () { // ("name not deleted successfully")// } else { // ("name deleted successfully")// } // if ((obj, "name")) { ("Name deleted successfully") } else { ("The name was not deleted successfully") }
5. Basic use of Reflect
What are the common methods in Reflect? It corresponds to Proxy one by one, and there are 13:
(target)
- Similar to ().
(target, prototype)
- Function that sets the object prototype. Returns a Boolean, and true if the update is successful.
(target)
- Similar to ()
(target)
- Similar to (). Returns a Boolean.
(target, propertyKey)
- Similar to (). If this property exists in the object, the corresponding property descriptor is returned, otherwise undefined.
(target, propertyKey, attributes)
- Similar to (). Common methods of returning true Reflect if set successfully
(target)
- Returns an array containing all its own attributes (not including inherited attributes). (similar to (), but not affected by enumerable).
(target, propertyKey)
- Determining whether an object has a certain property, the function of the in operator is exactly the same.
(target, propertyKey[, receiver])
- Gets the value of a property on the object, similar to target[name].
(target, propertyKey, value[, receiver])
- Function that assigns values to attributes. Returns a Boolean, and true if the update is successful.
(target, propertyKey)
- As the delete operator of the function, it is equivalent to executing delete target[name].
(target, thisArgument, argumentsList)
- A function can be called, and an array can be passed as a call parameter. Similar to () function.
(target, argumentsList[, newTarget])
- Performing new operations on the constructor is equivalent to executing new target(…args).
Then we can modify the operations on the original object in the previous Proxy case to Reflect to operate:
const obj = { name: "why", age: 18 } const objProxy = new Proxy(obj, { set: function(target, key, newValue, receiver) { // target[key] = newValue // 1. Benefit 1: The purpose of proxying the object: no longer directly operate the original object // 2. Benefit 2: The method returns the Boolean value, which can determine whether the operation is successful const isSuccess = (target, key, newValue) if (!isSuccess) { throw new Error(`set ${key} failure`) } }, get: function(target, key, receiver) { } }) // Operation agent object = "kobe" (obj)
The receiver
We found that when using getters and setters, there is aParameters of receiver, What is its function?
If our source object (obj) has accessor attributes of setter and getter, then the inside can be changed through receiver.this
;
const obj = { _name: "why", set name(newValue) { ("this:", this) // The default is obj this._name = newValue }, get name() { return this._name } } // = "aaaa" // () // = "kobe" const objProxy = new Proxy(obj, { set: function(target, key, newValue, receiver) { // target[key] = newValue // 1. Benefit 1: The purpose of proxying the object: no longer directly operate the original object // 2. Benefit 2: The method returns the Boolean value, which can determine whether the operation is successful /* 3. Benefits Three: > receiver is the outer Proxy object > /get last parameter, which can determine the point of this point of the object accessor setter/getter */ ("The setting method in proxy is called" + key) const isSuccess = (target, key, newValue, receiver) if (!isSuccess) { throw new Error(`set ${key} failure`) } }, get: function(target, key, receiver) { ("The method in proxy is called") return (target, key, receiver) } }) // Operation agent object = "kobe" ()
construct
function Person(name, age) { = name = age } function Student(name, age) { // (this, name, age) const _this = (Person, [name, age], Student) return _this } // const stu = new Student("why", 18) const stu = new Student("why", 18) (stu) (stu.__proto__ === )
This is the end of this article about Proxy-Reflect in JavaScript. For more related JavaScript Proxy-Reflect content, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!