This is the 20th day of my participation in the Genwen Challenge
No foreword, let’s get straight to the point!
Due to the length of the paper, IN order not to mess up, I first wrote a general idea of this paper, as shown in the figure above
A Proxy is a Proxy
So what is it? Check with typeof
console.log(typeof Proxy)//function
Copy the code
It can be known from the above:
Proxy
Is defined in thewindow
Global variable on- Its type is
function
And with a capital letter, we can guess that it’s not a normal function, it should be a constructor or a class.
Let’s try it, if we can just do it!
let proxy = Proxy(a)Copy the code
Uncaught TypeError: Constructor Proxy requires ‘new’
So let’s try new Proxy() in earnest, as follows:
let p = new Proxy(a)Copy the code
Uncaught TypeError: Cannot create a proxy with a non-object as target or handler. Cannot create a proxy with a non-object as target or handler. The answer is to pass the parameters as it wants
From the above error information, we can draw two important information:
Proxy
We take two arguments when constructing an object:target
andhandler
- The two parameters must be of type
object
So what do these two parameters target and handler represent?
In the beginning, I said Proxy means Proxy, meaning that it “proxies” for certain operations; The Internet has another interpretation:
Proxy can be understood as “interception”. A layer of “interception” is set up before the target object. When the outside world accesses the object, it must pass this layer of interception first.
Target is the target object to intercept (proxy). Handlers are used to customize interception behavior
Target is easy to understand, but the key is what can you put in this handler? What operations are used to intercept objects?
So, we guess: There must be a one-to-one method in handler that corresponds to object operations.
So let’s go back to how do we manipulate objects? For convenience, I’ll list all the ways you can manipulate objects
For example: js
let obj = {
name: 'alice',
showName() {
console.log(`my name is ${this.name}`)
}
}
Copy the code
- Get object properties
console.log(obj.name)//alice
Copy the code
- Add attributes to an object
obj.age = 12;
Copy the code
- Determines whether the property is in the object
console.log('age' in obj)//true
Copy the code
- Deleting object Properties
delete obj.age
Copy the code
- All properties of an object are iterated through various methods
console.log(Object.getOwnPropertyNames(obj));//["name", "showName"]
console.log(Object.getOwnPropertySymbols(obj));/ / []
console.log(Object.keys(obj))//["name", "showName"]
for (let key in obj){
console.log(key)
}// Print name showName respectively
Copy the code
- Gets the description object of a property of the object
let d = Object.getOwnPropertyDescriptor(obj,'name')
console.log(d)
//{value: "alice", writable: true, enumerable: true, configurable: true}
Copy the code
- Add one or more attributes to an Object using methods on Object
Object.defineProperty(obj,'age', {value:12.writable:true.enumerable:true.configurable:true
})
Object.defineProperties(obj,{
showAge: {value:function(){console.log(I this year `The ${this.age}At the age of `)},
writable:true.enumerable:true.configurable:true,},showInfo: {value:function(){console.log(I call `The ${this.name}This year, IThe ${this.age}At the age of `)},
writable:true.enumerable:true.configurable:true,}})Copy the code
- Gets the prototype object of an object
Object.getPrototypeOf(obj)
console.log(Object.getPrototypeOf(obj) === obj.__proto__)//true
Copy the code
- Sets the stereotype property object for an object
Object.setPrototypeOf(obj,null);
// Sets the object's prototype to NULL, or you can pass in other objects as its prototype
Copy the code
- Make an object unextensible, that is, you cannot add new attributes
Object.preventExtensions(obj)
Copy the code
- Check to see if an object is extensible
console.log(Object.isExtensible(obj));//false because the object is set to be unextensible
Copy the code
- If the object is of type function, objects of type function can perform the executed symbol () as well as.call() and.apply()
function fn(. args){
console.log(this,args)
}
fn(1.2.3);
fn.call(obj,1.2.3);
fn.apply(obj,[1.2.3]);
Copy the code
- Everything is an object. When an object is used as a constructor, the object can be used to generate a new object
function Person(){}
let p1 = new Person();
Copy the code
These are some operations on objects!
So if we go back to our handler in our new Proxy(Target,handler), we said that the handler is used to set up interception behavior, and what it intercepts is this set of operations on an object, and when an object does something, it triggers something that’s defined in the handler, And these things are essentially functions.
Therefore, we have a comprehensive understanding of Proxy, and know that it is actually a constructor. It can construct a Proxy object, which can do something on behalf of the target object. When performing an operation, it will execute the corresponding function of the operation. So the question is, what are the functions in handler? What are the operations?
Let’s do it one by one
The get method
The get method automatically accepts three parameters, target, propKey, and receiver, representing the target object to be propped up, the property on the object, and the proxy object, respectively. This method is used to intercept reads of properties such as proxy.foo and proxy[‘foo’].
var person = {
name: "Alice"
};
var proxy = new Proxy(person, {
get: function(target, propKey) {
if (propKey in target) {
return target[propKey];
} else {
throw new ReferenceError(`Prop name ${propKey} does not exist.`); }}}); proxy.name// "Alice"
proxy.age // Uncaught ReferenceError: Prop name age does not exist.
Copy the code
If you call a property that does not exist, it will return undefined. If you call a property that does not exist, it will return undefined.
And console.log(proxy === receiver) returns true
Set method
The set method automatically accepts four parameters: target, propKey, value, and Receiver, which represent the target object to be propped up, the property on the object, the value of the property, and the proxy object, respectively.
This method is used to intercept object property operations like proxy.foo = XXX or proxy[‘foo’] = XXX, for example:
var person = {
name: "Alice"
};
var proxy = new Proxy(person, {
set(target, propKey, value, receiver) {
console.log(` set${target} 的${propKey}Property with a value of${value}`);
target[propKey] = value
}
});
proxy.name = 'Tom'
proxy.age = 18
Copy the code
The results are as follows:
From the way
The HAS method takes the target, propKey, which intercepts the propKey in proxy operation and returns a Boolean value indicating whether the property exists. As follows:
var person = {
name: "Alice"
};
var proxy = new Proxy(person, {
has(target, propKey) {
return propKey in target
}
});
if('name' in proxy){
console.log(proxy.name)
}
Copy the code
The above results return Alice
DeleteProperty method
Accepts target, propKey, which intercepts the delete operation and returns a Boolean value indicating whether the delete was successful. Such as:
var person = {
name: "Alice"
};
var proxy = new Proxy(person, {
deleteProperty(target, propKey) {
return delete target[propKey]
}
});
console.log(delete proxy.name)//ture
console.log(proxy.name)//undefined
Copy the code
OwnKeys method
Acceptable target for interception Object. GetOwnPropertyNames (proxy), Object. GetOwnPropertySymbols (proxy), the Object. The keys (proxy), for… The in loop returns an array representing the keys that the object has, as follows:
var person = {
name: "Alice"
};
var proxy = new Proxy(person, {
ownKeys(target) {
return Object.getOwnPropertyNames(target)// To save trouble}});console.log(Object.getOwnPropertyNames(proxy))
Copy the code
Return/” name”
GetOwnPropertyDescriptor method
Receiving target and propKey, used to intercept the Object getOwnPropertyDescriptor (proxy, propKey), returns the attributes describe objects. As follows:
var person = {
name: "Alice"
};
var proxy = new Proxy(person, {
getOwnPropertyDescriptor(target,propKey){
return Object.getOwnPropertyDescriptor(target, propKey)
}
});
console.log(Object.getOwnPropertyDescriptor(proxy, 'name'))
Copy the code
The results are as follows:
DefineProperty method
Receive target, propKey, and propDesc, which represent the target object, the target object’s properties, and the property description configuration, respectively. Used to intercept operations on Object.defineProperty(proxy, propKey, propDesc) and Object.defineProperties(proxy, propDescs), for example:
var person = {};
var proxy = new Proxy(person, {
defineProperty(target,propKey,propKeypropDesc){
return Object.defineProperty(target, propKey, propKeypropDesc)
}
});
console.log(Object.defineProperty(proxy, 'name', {value:'Tom'}))
console.log(person.name)
Copy the code
PreventExtensions method
The Object preventExtensions(proxy) action is the target that receives the Object preventExtensions(proxy) action. The preventExtensions function is to make the Object unextensible, meaning that new properties can never be added. Such as:
var person = {
name: "Alice"
};
var proxy = new Proxy(person, {
preventExtensions(target){
return Object.preventExtensions(target)
}
});
Object.preventExtensions(proxy)
proxy.age = 11;
console.log(person)
Copy the code
The age added later was not successfully added
getPrototypeOf(target)
Using Object.getProtoTypeof (proxy) triggers a call that returns an Object
var person = {
name: "Alice"
};
var proxy = new Proxy(person, {
getPrototypeOf(target){
return Object.getPrototypeOf(target)
}
});
console.log(Object.getPrototypeOf(proxy))
Copy the code
isExtensible(target)
The call is triggered when using object.isextensible (proxy) and returns a Boolean value indicating whether it isExtensible, as follows:
var person = {
name: "Alice"
};
var proxy = new Proxy(person, {
isExtensible(target){
return Object.isExtensible(target)
}
});
console.log(Object.isExtensible(proxy))//true
Copy the code
setPrototypeOf(target, proto)
This function call is triggered when object.setPrototypeof (proxy, proto) is called, for example:
var person = {
name: "Alice"
};
let proto = {}
let proxy = new Proxy(person,{
setPrototypeOf(target,proto){
console.log(` set${target}The prototype for${proto}`);
return Object.setPrototypeOf(target,proto)
}
});
Object.setPrototypeOf(proxy,proto)
console.log(Object.getPrototypeOf(person) === proto)
Copy the code
The results are as follows
apply(target, object, args)
It receives three parameters: target, object, and args, representing the target object, this pointing to the calling function, and the parameter list. This is fired when a Proxy instance is called as a function, such as Proxy (… The args), proxy. Call (object,… The args), proxy. Apply (…). That is as follows:
function f (x,y){ return x + y}
let proxy = new Proxy(f,{
apply(target, object, args){
console.log('called f');
returnf.call(object,... args) } })console.log(proxy(1.2));
Copy the code
The results are as follows:
construct(target, args)
Receives target and args, indicating that the target function, the argument list, is invoked when a Proxy instance is used as a constructor, such as new Proxy (… Args), for example:
function F(){}let proxy = new Proxy(F,{
construct(target, args){
console.log('construct' is called);
return newtarget(... args) } })console.log(new proxy())
Copy the code
The results are as follows:
These methods are called catchers, which capture the different behavior of the object.
Let’s use a simple example to further clarify the relationship between the target object and the proxy object.
The following
var person = {
name: "Alice"
};
var proxy = new Proxy(person, {
set(target, propKey, value, receiver) {
console.log(` set${target} 的${propKey}Property with a value of${value}`);
target[propKey] = value
}
});
proxy.age = 18
person.sex = 'female'
console.log(person,proxy)
Copy the code
The result is shown in figure
From the above examples, we can draw the following four conclusions:
- The proxy object is not equal to the target object, it is the target object’s packaging
- The target object can be operated on directly or by a proxy object, and the two are related
- If the target object is manipulated directly, various interception behaviors defined by the agent are bypassed
- If we use a proxy, we want to embed the special behavior we define in the operations on the object, so we usually just manipulate the proxy object
If you’re still confused, let me show you what Proxy looks like. . It is a constructor that takes two parameters target and handler and returns the proxy object
function Proxy(target,handler){
/ /...
}
Copy the code
Now that you have a thorough understanding of Proxy, let’s take a look at its application. Since proxy mode is a very typical programming mode and can be used in many places, let’s take Vue3 data responsive system as an example.
Vue3 defines a series of reactive apis, such as Reactive, REF, etc., that update the UI when data changes and use Proxy at the bottom! I’m going to use Reactive
function reactive(obj) {
return new Proxy(obj, {
get(target, key) {
return target[key]
},
set(target, key, val) {
target[key] = val
// Update the interface when the data changes, so we consider that we need to update the user
// Execute the updata operation...}})}Copy the code
As you can see, the data object OBj is wrapped in Reactive as a proxy object. When the data changes, the set method is called, and some update operations are performed simultaneously
This is a typical proxy mode application
There should be no problem here, if you have any questions, please leave a message below to inform, thank you!
END~