- Before this section introduces the Proxy section, you need to know a little about metaprogramming
I. Metaprogramming
- Metaprogramming refers to the writing of a class of computer programs
Write or manipulate other programs (or themselves)
As their data, orDo some work at run time that should be done at compile time
. In many cases, it’s more efficient than writing all the code by hand. - The language in which the metaprogram is written is called the metalanguage, the language in which it is manipulated is called the target language,
The ability of a language to be its own metalanguage is called reflection!
- Starting with ES5, JS gets the pair
Support for Proxy,Reflect objects that allow you to intercept and define custom behavior for basic language operations
, for example (attribute lookup, assignment, enumeration, function call, etc.),With these two objects, Proxy and Reflect, you can do metaprogramming in JS
Summary of two.
1. Basic meaning
- Proxy Is used to modify certain operations
The default behavior
Is equivalent to making changes at the language level, so it belongs toMeta Programming, or programming a programming language
- Proxy can be understood as
Set up an intercept in front of the target
, external access to the object, must first pass this layer of interception. - So you can compare
Outside access to filter and rewrite
The original meaning of Proxy is Proxy. In JS, Proxy is used to Proxy some operations, as a Proxy - A simple example of intercepting a GET read operation
// Declare an interceptor object with the properties of the object to be listened on
var handler={
get:function(target,name){
if(target.hasOwnProperty(name)){
return The 'object contains${name}Attribute `
}else{ return 'object has no${name}Attribute ` } } } // Bind an interceptor to an obj object and create an instance of the interceptor var obj={name:'yiye'.f:(a)= >{}} var p=new Proxy(obj,handler) // 1. Use the properties of the Proxy instance directly console.log(p.name);// The object contains the name attribute console.log(p.age);// The object has no age attribute // 1.2 Assign a value to the Proxy instance (but it was intercepted, so the change does not take effect unless the Proxy tries to change it) p.name="Change" console.log(p.name);// The object contains the name attribute // 2. There is no intercepting function, so it is not a function console.log(p.f());//p.f is not a function // 3. Calling a function whose object does not exist prompts that the variable is not a function console.log(p.foo());//p.foo is not a function Copy the code
- You can bind a Proxy to an object as an object property
var obj={proxy:new Proxy(target,handler)}
Proxy has prototype objects that can also be used as other objects, object.create (obj)
var handler={
get:function(target,proxyKey){
return 35
}
}
var a={name:'hh'} // Use the proxy in the form of j.proxy.xxx New Proxy(obj,handler var obj={proxy:new Proxy(Object.create(a),handler)} console.log(obj.proxy.name);/ / 35 console.log(obj.proxy.age);/ / 35 Copy the code
Parameters of 2.
- New Proxy(target,handler) takes two parameters, representing the target object and the internal listener object, and handler is an empty {} object
Indicates that interception is not set, which is equivalent to directly accessing the original object
- Handler internal listening method is
The set of
There are three parameters, (target,name,value),Target indicates the target object, name indicates the attribute name, and value indicates the value
The number and meaning of parameters vary depending on how the handler listener listens
- Here is an example of listening for a set operation
// Declare an interceptor
var handler={
set:function(target,name,value){
target[name]="set+"+value;
}
} // Bind an interceptor to an obj object and create an instance of the interceptor var obj={name:'yiye'.f:(a)= >{}} var p=new Proxy(obj,handler) // 1. Use the properties of the Proxy instance directly console.log(p.name);//yiye // 1.2 Assign a value to the Proxy instance p.name="Change" console.log(p.name);/ / set + change Copy the code
Proxy as a design pattern
- There is a design pattern in programming that is
Proxy Pattern
- An agent is a category that can
As an interface to something else
, agents can act as interfaces to anything: network connections, large objects in memory, files or other resources that are expensive or impossible to copy. Reference counting in the garbage collection mechanism uses the proxy pattern
- When an object is referenced, proxies are created, and each proxy references the object. The operations that are performed on the agent are passed to the object.
Once all the agents are gone, the object is cleaned up and garbage collected
Proxy instance methods
- There are 13 methods for proxy instance, and only a few are used here.
1. get()
- The get method is used to intercept object properties
Read operation
Takes three arguments, the target object, the property name, andProxy instance itself
(strictly speaking, the object for which the action is performed), the last of which is optional. - Access properties that do not exist on the target object,
It also performs get reads that the proxy listens for
.If there is no interceptor, then undefined is returned
The listener's get method can be inherited!
var a={name:'a'}
var proxy=new Proxy(a,{
get(target,name,value){
if(target.hasOwnProperty(name)) return 'get+'+target[name]
return 'This property does not exist'
} }) var child=Object.create(proxy) console.log(child);//{name: "eee",__proto__:Proxy}, where Proxy is the listener object, not the function console.log(child.__proto__);// This attribute does not exist console.log(child.prototype);// This attribute does not exist // Point to the property of the prototype object when the object child does not have a property name console.log(child.name);//get+a // Add an attribute name to the object, which points to the attribute of the object itself child.name='eee' console.log(child.name);//eee Copy the code
- Use proxy to complete chained calls
var pipe = function (value) {
var funcStack = []; // Store the function
var oproxy = new Proxy({}, { get : function (pipeObject, fnName) {
if (fnName === 'get') {
return funcStack.reduce(function (val, fn) { return fn(val); },value); } funcStack.push(window[fnName]); return oproxy; // Return proxy } }); return oproxy; // Return proxy } var double = n= > n * 2; var pow = n= > n * n; var reverseInt = n= > n.toString().split("").reverse().join("") | 0; // Reverse the number // reverseInt(pow(double(3))); //3*2=6,6*6=36, the reverse order of 36 is 63 console.log(pipe(3).double.pow.reverseInt.get) / / 63 Copy the code
2. set()
- The set method takes four arguments, which are
The target object, property name, property value, proxy instance itself, and the last parameter is optional
- An example:
An error occurs when the value of the age attribute is greater than 200
var obj={age:10.name:'yiye'}
var person=new Proxy(obj,{
set:function(newobj,name,val,pro){
if(name==='age') { if(val>200) { throw new Error("this age is too max") } } newobj[name]=val;/ / update } }) console.log(person);//Proxy {age: 10, name: "yiye"} console.log(obj);//{age: 10, name: "yiye"} // Modify the properties of the target object directly obj.age=210 console.log(obj);//{age: 210, name: "yiye"} console.log(person);//Proxy {age: 210, name: "yiye"} // Modify the properties of the proxy object. person.age=20;// No error will be reported, and the value will remain console.log(person);//Proxy {age: 20, name: "yiye"} console.log(obj);//{age: 20, name: "yiye"} // person.age=220; // The limit is exceeded console.log(obj); //Uncaught Error: this age is too max console.log(person); //Uncaught Error: this age is too max Copy the code
limit
- When a property of an object
No, then the set listener will be invalidated
var obj={age:10.name:'yi'}
Object.defineProperty(obj,'foo', { writable:false. value:'foo'
})
var person=new Proxy(obj,{ set:function(target,name,value,receiver){ target[name]="set+"+value; } }) console.log(person);//Proxy {age: 10, name: "yi", foo: "foo"} // Modify the foo attribute person.foo="f" // However, the change does not take effect. console.log(person);//Proxy {age: 10, name: "yi", foo: "foo"} // Modify other attributes at this time, it will take effect! person.age=10000 person.name='good' console.log(person);//Proxy {age: "set+10000", name: "set+good", foo: "foo"} Copy the code
3. apply()
The apply method intercepts three types of function calls. , call binding, apply binding!
- Accepts three parameters, namely the target object, the context of the target object, and the array of parameters of the target object
// 1. Create a proxy that listens for apply operations
var sum=function(a,b){
return a+b
}
var proxy=new Proxy(sum,{
apply:function(target,ctx,args){ console.log(target,ctx,args); / *ƒ (a, b) { return a+b } undefined (2) [1, 2] * / returnsum(... args); } }) // 2. Function call console.log(proxy(1.2));/ / 3 // 3 console.log(proxy.call(null.2.3));/ / 5 // 4 console.log(proxy.apply(null[4.5]));/ / 9 Copy the code
3. Proxy. Revocable ()
- Proxy.revocable() returns a cancelable Proxy instance
- The return is an object, object of
The proxy attribute is the proxy instance, and the REVOKE attribute is a function that cancellations the proxy instance
If you access the proxy instance after executing REVOKE, an error is thrown
var obj={age:22.name:'ww'}
var handler={}
var {proxy,revoke}=Proxy.revocable(obj,handler);
console.log(proxy);//Proxy {age: 22, name: "ww"}
// Revoke the agent with revoke
revoke(); console.log(proxy);//Proxy {} // If you try to access the properties of the proxy instance again, an error message will be displayed indicating that the proxy has been canceled console.log(proxy.age);// Cannot perform 'get' on a proxy that has been revoked Copy the code
A. This b. this C. this D. this
- The proxy does the proxy, but this proxy
Does not change the direction of this
- If you do not bind the reference to this in the listening method, then the rule to which this refers is used
var obj={
m:function(){
console.log(this===proxy)
}
}
var handler={} var proxy=new Proxy(obj,handler) // The obj object calls the m attribute method, so internally this refers to obj obj.m();//false // Proxy instance object calls m property method, so this refers to proxy internally proxy.m();//true Copy the code
If you need to bind this to the target target object, then
const target = new Date('2015-01-01');
const handler = {
get(target, prop) {
if (prop === 'getDate') {
return target.getDate.bind(target);
} return Reflect.get(target, prop); } }; const proxy = new Proxy(target, handler); console.log(target.getDate());/ / 1 // Even if the method is called from the proxy object, this inside the property still points to the target object console.log(proxy.getDate()) / / 1 Copy the code