Proxies
To create a proxy object, we use the Proxy constructor -new Proxy();
. The proxy constructor takes two items:
- the object that it will be the proxy for
- an object containing the list of methods it will handle for the proxied object
The second object is called thehandler.
A Pass Through Proxy
The simplest way to create a proxy is to provide an object and then an empty handler object.
var richard = {status: 'looking for work'};
var agent = new Proxy(richard, {});
agent.status; // returns 'looking for work'
The above doesn't actually do anything special with the proxy - it just passes the request directly to the source object! If we want the proxy object to actually intercept the request, that's what the handler object is for!
The key to making Proxies useful is the handler object that's passed as the second object to the Proxy constructor. The handler object is made up of a methods that will be used for property access. Let's look at theget
:
Get Trap
Theget
trap is used to "intercept" calls to properties:
const richard = {status: 'looking for work'};
const handler = {
get(target, propName) {
console.log(target); // the `richard` object, not `handler` and not `agent`
console.log(propName); // the name of the property the proxy (`agent` in this case) is checking
}
};
const agent = new Proxy(richard, handler);
agent.status; // logs out the richard object (not the agent object!) and
//the name of the property being accessed (`status`)
In the code above, thehandler
object has aget
method (called a "trap" since it's being used in a Proxy). When the codeagent.status;
is run on the last line, because theget
trap exists, it "intercepts" the call to get thestatus
property and runs theget
trap function. This will log out the target object of the proxy (therichard
object) and then logs out the name of the property being requested (thestatus
property). And that's all it does! _It doesn't actually log out the property! This is important -_if a trap is used, you need to make sure you provide all the functionality for that specific trap.
위의 코드에서
handler
객체에는get
메소드가 있습니다 (Proxy에서 사용되기 때문에 "trap"이라고 함). 코드agent.status;
는get
트랩이 존재하기 때문에 마지막 라인에서 실행되며, 호출을 가로채어status
속성을 가져오고get
트랩 기능을 실행합니다. 그러면 Proxy의 대상 객체 (richard
객체)가 로그 아웃되고 요청된 속성의 이름 (status
속성)이 로그 아웃됩니다. 그게 전부입니다! 실제로 로그 아웃하지 않습니다! 이것은 중요합니다. trap을 사용하는 경우 특정 trap에 대한 모든 기능을 제공해야합니다.
Accessing the Target object from inside the proxy
If we wanted to actually provide the real result, we would need to return the property on the target object:
const richard = {status: 'looking for work'};
const handler = {
get(target, propName) {
console.log(target);
console.log(propName);
return target[propName];
}
};
const agent = new Proxy(richard, handler);
agent.status; // (1)logs the richard object, (2)logs the property being accessed, (3)returns the text in richard.status
Notice we added thereturn target[propName];
as the last line of theget
trap. This will access the property on the target object and will return it.
Having the proxy return info, directly
Alternatively, we could use the proxy to provide direct feedback:
const richard = {status: 'looking for work'};
const handler = {
get(target, propName) {
return `He's following many leads, so you should offer a contract as soon as possible!`;
}
};
const agent = new Proxy(richard, handler);
agent.status; // returns the text `He's following many leads, so you should offer a contract as soon as possible!`
With this code, the Proxy doesn't even check the target object, it just directly responds to the calling code.
So theget
trap will take over whenever any property on the proxy is accessed. If we want to intercept calls to_change_properties, then theset
trap needs to be used!
Theset
trap is used for intercepting code that will change a property. Theset
trap receives: the object it proxies the property that is being set the new value for the proxy
const richard = {status: 'looking for work'};
const handler = {
set(target, propName, value) {
if (propName === 'payRate') { // if the pay is being set, take 15% as commission
value = value * 0.85;
}
target[propName] = value;
}
};
const agent = new Proxy(richard, handler);
agent.payRate = 1000; // set the actor's pay to $1,000
agent.payRate; // $850 the actor's actual pay
In the code above, notice that theset
trap checks to see if thepayRate
property is being set. If it is, then the proxy (the agent) takes 15 percent off the top for her own commission! Then, when the actor's pay is set to one thousand dollars, since thepayRate
property was used, the code took 15% off the top and set the actualpayRate
property to850
;
Other Traps
So we've looked at theget
andset
traps (which are probably the ones you'll use most often), but there are actually a total of 13 different traps that can be used in a handler!
- the get trap lets the proxy handle calls to property access
- the set trap lets the proxy handle setting the property to a new value
- the apply trap lets the proxy handle being invoked (the object being proxied is a function)
- the has trap lets the proxy handle the using
in
operator - the deleteProperty trap lets the proxy handle if a property is deleted
- the ownKeys trap lets the proxy handle when all keys are requested
- the construct trap lets the proxy handle when the proxy is used with the
new
keyword as a constructor - the defineProperty trap lets the proxy handle when defineProperty is used to create a new property on the object
- the getOwnPropertyDescriptor trap lets the proxy handle getting the property's descriptors
- the preventExtenions trap lets the proxy handle calls to
Object.preventExtensions()
on the proxy object - the isExtensible trap lets the proxy handle calls to
Object.isExtensible
on the proxy object - the getPrototypeOf trap lets the proxy handle calls to
Object.getPrototypeOf
on the proxy object - the setPrototypeOf trap lets the proxy handle calls to
Object.setPrototypeOf
on the proxy object
As you can see, there are a lot of traps that let the proxy manage how it handles calls back and forth to the proxied object.