Skip to content

Instantly share code, notes, and snippets.

@androide-osorio
Last active October 13, 2016 16:30
Show Gist options
  • Save androide-osorio/f9e05db8d0c0de70d04f8b1f942e657d to your computer and use it in GitHub Desktop.
Save androide-osorio/f9e05db8d0c0de70d04f8b1f942e657d to your computer and use it in GitHub Desktop.
ES2015 Roadtrip to awesomeness - Proxies
/*
* Proxies
*/
/*
* Proxies allow to override the default behavior
* from an object's default operations.
*
* Proxies enable creation of objects with the full range of behaviors available to host objects.
* Can be used for interception, object virtualization, logging/profiling, etc.
*/
const person = { name: 'Andrew', age: 25 };
// a proxy receives 2 things:
// 1 -> the target object to intercept.
// 2 -> the "handler", where all the operations that will be
// intercepted or overwritten are specified
const personProxy = new Proxy(person, {
// each of the methods or properties
// defined here are called "traps"
get(target, key) {
console.log('someone is asking for', target, key);
return 'Fck you 🇩🇪';
}
set(target, key, value) {
if(typeof value === 'string') {
target[key] = value.trim().toUpperCase();
}
}
});
// will output:
// -> someone is asking for [Object object] name
// -> fck you [germany flag]
console.log(personProxy.name);
// testing new setter
personProxy.motto = " I'm the fucking boss!!! ";
console.log(personProxy.motto); // -> "I'M THE FUCKING BOSS!!!"
// Proxies have a reference to the original object,
// they do not copy its values. If you modify
// the original object, those changes will be reflected
// in the proxy object and viceversa
const dummyObject = {};
const dummyObjectProxy = new Proxy(dummyObject, {
get(target, key) {
return target[key];
},
set(target, key, value) {
target[key] = value;
}
});
console.assert(dummyObject !== dummyObjectProxy); // -> true
// if we change the original object directly,
// the change will be reflected in the proxy as well
dummyObject.foo = true;
console.assert(dummyObjectProxy.foo === true); // -> passes
dummyObjectProxy.bar = false
console.assert(dummyObject.bar === false); // -> passes
// --------------------------------------------------
// practical example
const phoneHandler = {
set(target, key, value) {
target[key] = value.match(/[0-9]/g).join('');
},
get(target, key) {
const phoneRegex = /(\d{3})(\d{3})(\d{4})/;
return target[key].replace(phoneRegex, '($1)-$2-$3')
}
};
const phoneNumbers = new Proxy({}, phoneHandler);
phoneNumbers.work = '(555) 555-5555';
console.log(phoneNumbers.work); // -> "(555)-555-5555"
// -----------------------------------------------------
// PROXY HANDLERS
// the handlers that can be used in proxy are the same
// ones accesible using the reflection API. These hooks
// or traps refer to JavaScript's internal methods
// full list here https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Proxy
// Here is a Proxy where we're defining the same behaviour as the default:
const proxy = new Proxy({}, {
apply: Reflect.apply,
construct: Reflect.construct,
defineProperty: Reflect.defineProperty,
getOwnPropertyDescriptor: Reflect.getOwnPropertyDescriptor,
deleteProperty: Reflect.deleteProperty,
getPrototypeOf: Reflect.getPrototypeOf,
setPrototypeOf: Reflect.setPrototypeOf,
isExtensible: Reflect.isExtensible,
preventExtensions: Reflect.preventExtensions,
get: Reflect.get,
set: Reflect.set,
has: Reflect.has,
ownKeys: Reflect.ownKeys,
});
// -----------------------------------------------------
// REVOCABLE PROXIES
// -----------------------------------------------------
// proxies can be revoked, which means the proxy object
// would no longer be usable.
// This could be useful when you need a temporary proxy
// that needs to garbage collected later on
const revocableProxy = Proxy.revocable({ foo: 'bar' }, {
get(target, property) {
const prop = Reflect.get(this, peroperty);
if(typeof prop === 'string') {
return target[property].toUpperCase();
}
return prop;
}
});
// a revocable proxy returns an object containing
// the actual proxy object, and a revoke() method
console.log(revocableProxy);
console.log(revocableProxy.foo); // -> "BAR"
// revoke the proxy
revocableProxy.revoke();
// once a proxy is revoked, all of its handlers
// will return a TypeError
console.log(revocableProxy.foo); // -> TypeError
@androide-osorio
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment