Metaprogramming refers to developers “programming the language itself”. Generally, the programming language exposes some APIs for developers to operate certain features of the language itself.
Starting from ES6, Proxy and Reflect features have been added, expanding meta programming (Meta Programming) capabilities, allowing interception and customization of basic language operation behaviors (such as attribute lookup, assignment, enumeration, function call, etc.).
Proxy(proxy)
Proxy is a new feature added in ES6. It can "proxy" the native behavior of the object and replace it with execution Custom behavior.
Proxy can be understood as setting up a layer of "interception" before the target object. External access to the object must first pass through this layer of interception, so it provides a mechanism that can Filter and rewrite external access. The original meaning of the word Proxy is agency. It is used here to mean that it "acts on behalf of" certain operations. It can be translated as "agent".
Proxy objects are used to define user-defined behaviors for basic operations (such as property lookup, assignment, enumeration, method calling, etc.).
Create a Proxy object:
##target: target The object can be any type of object, such as an array, a function, or even another proxy object.
handlert: Handler object, which contains a set of proxy methods to control various behaviors of the generated proxy objects.
Methods of Proxy object:
Proxy.revocable(target, handler): used to create a revocable proxy object.
The processor object has a total of 14 proxy methods:
handler.getPrototypeOf(): Triggered when reading the prototype of the proxy object This operation, such as when executing Object.getPrototypeOf(proxy).
handler.setPrototypeOf(): This operation is triggered when setting the prototype of the proxy object, such as when executing Object.setPrototypeOf(proxy, null).
handler.isExtensible(): This operation is triggered when determining whether a proxy object is extensible, such as when executing Object.isExtensible(proxy).
handler.preventExtensions(): This operation is triggered when making a proxy object non-extensible, such as when executing Object.preventExtensions(proxy).
handler.getOwnPropertyDescriptor(): This operation is triggered when obtaining the property description of a property of the proxy object, such as when executing Object.getOwnPropertyDescriptor(proxy, “foo”).
handler.defineProperty(): This operation is triggered when defining the property description of a property of the proxy object, such as when executing Object.defineProperty(proxy, “foo”, {}) hour.
handler.has(): This operation is triggered when determining whether the proxy object has a certain attribute, such as when executing "foo" in proxy.
handler.get(): This operation is triggered when reading a certain property of the proxy object, such as when executing proxy.foo.
handler.set(): This operation is triggered when assigning a value to a certain attribute of the proxy object, such as when executing proxy.foo = 1.
handler.deleteProperty(): This operation is triggered when a property of the proxy object is deleted, such as when delete proxy.foo is executed.
handler.enumerate(): This operation is triggered when traversing the properties of the proxy object, such as when executing for(i in proxy){}.
handler.ownKeys(): This operation is triggered when all property keys of the proxy object are obtained, such as when executing Object.getOwnPropertyNames(proxy).
handler.apply(): This operation is triggered when a proxy object whose target object is a function is called, such as when executing proxy().
handler.construct(): This operation is triggered when constructing an instance of a proxy object whose target object is the constructor, such as when executing new proxy().
Interception of reading operations of attribute values:
In the above code, Proxy( The proxy) object defines a target and a handle, and the handle implements a get capture method. Through this method, the proxied object no longer returns undefined for undefined properties, but returns a number of 42.
Intercept the assignment operation of attribute value:
Above In the code, the set processing function is set. If the properties of the object we are listening to are changed, then this handler will be called. At the same time, through the parameters, we can know which property was changed and what value it was changed to.
The same interceptor function can be set to intercept multiple operations:
The Proxy.revocable method is used to create a revocable proxy object. Once a proxy object is revoked, it will become almost completely unavailable. Any proxy operation performed on it will throw a TypeError exception. .
Reflect(reflection)
Introduced in ES6 Reflect is another metaprogramming feature that allows us to directly manipulate the native behavior of objects. There is a one-to-one correspondence between Reflect's controllable behaviors and Proxy's proxies, which makes it easy to use Reflect to call native behaviors in Proxy's custom methods.
Reflection (reflection) is a valuable language feature that promotes meta-programming. It can dynamically display the characteristics of the program itself while the program is running.
The Reflect object provides 14 static methods. Their names happen to be the same as the names of the 14 proxy processor methods. Several of these 14 methods happen to be on the Object object. Methods of the same name also exist, and while they function similarly, there are subtle differences.
Reflect.apply(): Call a function and pass in an array as a calling parameter. Similar to Function.prototype.apply().
Reflect.construct(): Performing a new operation on the constructor is equivalent to executing new target(...args).
Reflect.defineProperty(): Similar to Object.defineProperty().
Reflect.deleteProperty(): Deleting a property of the object is equivalent to executing delete target[name].
Reflect.enumerate(): This method will return an iterator containing all enumerable own string properties and inherited string properties of the target object, for...in operation It is these properties that are traversed.
Reflect.get(): Get the value of a certain attribute on the object, similar to target[name].
Reflect.getOwnPropertyDescriptor(): Similar to Object.getOwnPropertyDescriptor().
Reflect.getPrototypeOf(): Similar to Object.getPrototypeOf().
Reflect.has(): Determines whether an object has a certain attribute. It has the same function as the in operator.
Reflect.isExtensible(): Similar to Object.isExtensible().
Reflect.ownKeys(): Returns an array containing all its own properties (excluding inherited properties).
Reflect.preventExtensions(): Similar to Object.preventExtensions().
Reflect.set(): Set the value of an attribute on the object, similar to target[name] = val.
Reflect.setPrototypeOf(): Similar to Object.setPrototypeOf().
In the above code, the Proxy method intercepts the attribute assignment behavior of the target object and uses the Reflect.set method to The value assigned to the object's property.
Why use Reflect:
Put some methods of the Object object that are obviously internal to the language (such as Object.defineProperty) into Reflect on the object. At this stage, some methods are deployed on both Object and Reflect objects, and new methods in the future will be deployed only on Reflect objects.
Modify the return results of some Object methods to make them more reasonable. For example, Object.defineProperty(obj, name, desc) will throw an error when the property cannot be defined, while Reflect.defineProperty(obj, name, desc) will return false.
Let Object operations become functional behaviors. Some Object operations are imperative, such as name in obj and delete obj[name], while Reflect.has(obj, name) and Reflect.deleteProperty(obj, name) turn them into functional behaviors.
The methods of the Reflect object correspond to the methods of the Proxy object one-to-one. As long as it is a method of the Proxy object, the corresponding method can be found on the Reflect object. This allows the Proxy object to easily call the corresponding Reflect method to complete the default behavior and serve as the basis for modifying the behavior. In other words, no matter how Proxy modifies the default behavior, you can always get the default behavior on Reflect.
In the above code, each interception operation (get, delete, has) of the Proxy object internally calls the corresponding Reflect method , to ensure that the native behavior can be executed normally. The added work is to output a line of log for each operation. With the Reflect object, many operations will be easier to read.
The above is the detailed content of ES6 new features development WeChat applet (6). For more information, please follow other related articles on the PHP Chinese website!