Proxy Traps
We went over Proxy and how it handles or intercepts incoming operations to a target object in the last blog post. Handler functions are called traps because they trap calls to the target object.
Thirteen internals traps were introduced in ES2015.
| Internal Method | Handler Method |
|---|---|
| [[GetPrototypeOf]] | getPrototypeOf |
| [[SetPrototypeOf]] | setPrototypeOf |
| [[IsExtensible]] | isExtensible |
| [[PreventExtensions]] | preventExtensions |
| [[GetOwnProperty]] | getOwnPropertyDescriptor |
| [[DefineOwnProperty]] | defineProperty |
| [[HasProperty]] | has |
| [[Get]] | get |
| [[Set]] | set |
| [[Delete]] | deleteProperty |
| [[OwnPropertyKeys]] | ownKeys |
| [[Call]] | call |
| [[Construct]] | construct |
You can read more and see the list here.
We will not go over all of them but a few that you would use frequently.
Get, Set & Delete
Get, Set and Delete are relatively straightforward. They allow you to read, write and remove from the target object.
const target = {
id: 1,
name: "John Doe",
age: 42,
income: 70000,
hobby: "Dancing"
};
const handler = {
get: function (target, property) {
if (["age", "income"].includes(property)) {
return `Access Denied, ${property} is restricted.`;
}
return Reflect.get(...arguments);
},
set: function (target, property, value) {
if (property === "name") {
target[property] = `${value} Doe`;
} else {
target[property] = value;
}
return true; // set and delete should return true or false based on the success
},
deleteProperty: function (target, property, value) {
if (property === "id") {
throw new Error("Required Property. Cannot Delete.");
}
delete target[property];
return true; // set and delete should return true or false based on the success
}
};
const proxy = new Proxy(target, handler);
// Get
console.log(proxy.name); // John Doe
console.log(proxy.age); // Access Denied, age is restricted.
console.log(proxy.income); // Access Denied, income is restricted.
console.log(proxy.hobby); // Dancing
// Set
proxy.name = "Jane"
proxy.age = 40;
console.log(proxy.name); // Jane Does
console.log(proxy.age); // Access Denied, age is restricted.
console.log(target.age); // 40
// Delete
console.log(delete proxy.id); // Required Property. Cannot Delete.
console.log(proxy.id); // 1
console.log(delete proxy.hobby); // true
console.log(proxy.hobby); // undefined
ownKeys
Object.keys or for..in loops are intercepted by ownKeys.
const target = {
id: 1,
name: "John Doe",
age: 42,
income: 70000,
hobby: "Dancing"
};
const handler = {
ownKeys: (target, property, value) => {
return Object.keys(target); // returns all keys from object
}
};
const proxy = new Proxy(target, handler);
for (let key in proxy) {
console.log(key); // id, name, age, income, hobby
}
We can use filter to filter out values (like sensitive information).
const target = {
id: 1,
name: "John Doe",
age: 42,
income: 70000,
hobby: "Dancing"
};
const handler = {
ownKeys: (target, property, value) => {
return Object.keys(target).filter((value) => !["age", "income"].includes(value));
}
};
const proxy = new Proxy(target, handler);
for (let key in proxy) {
console.log(key); // id, name, hobby
}
has
The has trap intercepts in calls.
const budget = {
"minimum": 500,
"maximum": 10000
};
const handler = {
has(target, property) {
return property >= budget.minimum && property <= budget.maximum;
}
};
const expenseRange = new Proxy(budget, handler);
console.log(5000 in expenseRange); // true
console.log(10001 in expenseRange); // false