The Proxy object is used in place of the original object. It is used to create some kind of filter of the object: it can determine what kind of values can be set, what properties can be deleted, whether can we even get some value or they are restricted.
Basic structure
To create proxy we use syntaxis: Proxy(target, handler)
:
- target - the original object, we want to proxy;
- handler - an object consisted of traps, that determine which operations are intercepted and how to redefine them.
Let's look at the example with empty handler
(all operations are implemented on the original object):
const target = {
name: "Mary",
status: "Online"
};
const handler = {};
const proxy = new Proxy(target, handler);
proxy.name = "Ann";
console.log(proxy.name); // Ann
for (let key in proxy) {
console.log(key); // name status
}
-
proxy.name =
sets value on target; -
proxy.name
returns value from target; - Iteration of keys in proxy returns keys from target.
Without handler, proxy just transfers all operations on target.
Handler
The most used traps in handler:
- get - reading properties in target;
- set - setting values to properties in target;
- deleteProperty - controling deletion of properties
Trap "get"
The get trap takes the following arguments:
- target - the same target from Proxy argument;
- prop - the property;
-
receiver -
this
value. Usually it's either the proxy or an object that inherits from the proxy
Let's create some simple handler:
const target = {
name: "Mary",
status: "Online"
};
const handler = {
get(target, prop) {
if (prop in target) {
return target[prop];
} else {
return "no info";
}
}
};
const proxy = new Proxy(target, handler);
console.log(proxy.name); // Ann
console.log(proxy.contact); // no info
Trap "set"
This trap is useful when we want some validation before setting values. It takes the same arguments as get
plus value
:
- target - the same target from Proxy argument;
- prop - the property;
- value - the value to set for the property;
-
receiver -
this
value. Usually it's either the proxy or an object that inherits from the proxy
const object = {
name: "Mary",
status: "Online"
};
const handler = {
set(target, prop, value) {
if (prop in target && typeof value === 'string') {
target[prop] = value;
return true;
} else {
return false;
}
}
};
const proxy = new Proxy(object, handler);
proxy.name = "Ann";
proxy.status = false; // can't set since the value type is boolean
console.log(proxy.name); // Ann
console.log(proxy.status); // Online
set
has to returntrue
if we write the value andfalse
if there is an error;
Trap "deleteProperty"
Let's say we don't want the password
to be accessed anyhow in our object:
const user = {
name: "Mary",
_password: "******"
};
const handler = {
get(target, prop) {
if (prop === "_password") {
throw new Error("Access denied")
} else {
return target[prop];
}
},
set(target, prop, value) {
if (prop === "_password") {
throw new Error("Access denied")
} else {
target[prop] = value;
return true;
}
},
deleteProperty(target, prop) {
if (prop === "_password") {
throw new Error("Access denied")
} else {
delete target[prop];
return true;
}
}
}
const proxyUser = new Proxy(user, handler);
try {
console.log(proxyUser._password);
} catch(e) {
console.log(e.message);
}
// Access denied
Private properties
Let's say we have some method that reaches the private property:
const user = {
name: "Mary",
_password: "******",
getPassword() {
return this._password;
}
};
const handler = {
get(target, prop) {
if (prop.startsWith("_")) {
throw new Error("Access denied")
}
return target[prop];
}
}
const proxyUser = new Proxy(user, handler);
try {
console.log(proxyUser.getPassword());
} catch(e) {
console.log(e.message);
}
// "Access denied"
Here, we will get error and denied access.
What if we want our method to work? We have to bind this
not to the proxy but to the target. Then the method will be called upon the target, not proxy:
const handler = {
get(target, prop) {
if (prop.startsWith("_")) {
throw new Error("Access denied")
}
const value = target[prop];
return (typeof value === 'function') ? value.bind(target) : value;
}
}
Now upon calling proxyUser.getPassword()
we will get "******"
.
Top comments (0)