En nuestro repaso por las novedades de ECMAScript 2015 nos encontramos con el objeto Proxy. El objeto Proxy se utiliza para personalizar los comportamientos de operaciones básicas como:
- observación de propiedades
- asignaciones
- enumeraciones
- funciones invocación
- etc.
Esto lo hace interceptando las llamadas a dichas operaciones y manipulando la respuesta.
Los Proxies de ES6 no tienen forma de ser definidos mediante ES5, por lo que es una característica NO SOPORTADA por los transpiladores como Babel, ni mediante polyfills. La única forma de utilizar proxies, de momento, es que lo soporte directamente el navegador.
Definición
Un proxy se define mediante un handler (objeto que gestiona las intercepciones a propiedades del proxy) y un target (objeto sobre el que queremos construir el proxy)
La sintaxis de declaración de un proxy sería la siguiente:
let proxy = new Proxy(target, handler);
También podríamos crear un proxy revocable, es decir, que quedará inservible después de utilizar el método revoke(), devolviéndonos un TypeError cuando se intenten utilizar sus interceptores. Veamos como usarlo:
var revocable = Proxy.revocable({}, {
get: function(target, prop) {
return "property: [" + prop + "]";
}
});
var proxy = revocable.proxy;
console.log(proxy.foo); // "property [foo]"
revocable.revoke();
console.log(proxy.foo); // lanza TypeError
proxy.foo = 1 // lanza TypeError
delete proxy.foo; // lanza TypeError
typeof proxy // en este caso no se utiliza el interceptor del proxy, por lo que no hay error
Veamos ahora un ejemplo básico donde interceptamos el método de acceso a las propiedades del objeto, de modo que si la propiedad no existe, nos devuelva el valor «-1»:
var handler = {
get: function(target, propertyKey){
return name in propertyKey?
propertyKey[name] : -1;
}
};
let proxy = new Proxy({}, handler);
p.a = 1;
p.b = undefined;
console.log(p.a, p.b, p.c);
//1, undefined, -1
Interceptores
Los métodos del handler con los que podemos interceptar al proxy son los siguientes:
- handler.getPrototypeOf(target): Intercepta Object.getPrototypeOf.
-
handler.setPrototypeOf(target, prototype): Intercepta Object.setPrototypeOf.
-
handler.isExtensible(target): Intercepta Object.isExtensible.
-
handler.preventExtensions(target): Intercepta Object.preventExtensions.
-
handler.getOwnPropertyDescriptor(target, property): Intercepta Object.getOwnPropertyDescriptor.
-
handler.defineProperty(target, property, descriptor): Intercepta Object.defineProperty.
-
handler.has(target, property): Intercepta el operador in.
-
handler.get(target, property, receiver): Intercepta el getter de las propiedades.
-
handler.set(target, property, value, receiver): Intercepta el setter de las propiedades
-
handler.deleteProperty(target, property): Intercepta el operador delete.
-
handler.ownKeys(target): Intercepta Object.getOwnPropertyNames.
-
handler.apply(target, thisArg, argumentsList): Intercepta la función call.
-
handler.construct(target, argumentsList, newTarget): Intercepta el operador new.
Ejemplos de uso de proxies
Veamos un par de ejemplos.
En primer lugar, un Proxy de redirección: Lo único que hace es redirigir todas las operaciones que se hacen sobre el mismo, hacia el target al que apunta:
var target = {};
var p = new Proxy(target, {});
p.a = 37; // operation forwarded to the target
console.log(target.a); // 37. The operation has been properly forwarded
Y otro ejemplo sería un Proxy de validación
let validator = {
set: function(obj, prop, value) {
if (prop === 'age') {
if (!Number.isInteger(value)) {
throw new TypeError('La edad tiene que ser un valor entero');
}
if (value < 0) {
throw new RangeError('Edad inválida');
}
}
// comportamiento por defecto del setter
obj[prop] = value;
}
};
let person = new Proxy({}, validator);
person.age = 100;
console.log(person.age); // 100
person.age = 'young'; // Lanza excepción
person.age = -5; // Lanza excepción
Puedes encontrar más ejemplos en la documentación de Mozilla Foundation para el objeto Proxy.
Conclusiones
Los proxies nos permiten alterar el comportamiento de algunas operaciones básicas de los objetos, pero ten cuidado si los quieres utilizar en webs hoy en día, ya que aún no está soportado por todos los navegadores, y esta característica no se puede emular en ES5 con transpiladores o polyfills.
En tod caso, ¡a mi me encanta su potencial!
¿Y a ti?¿Te parecen útiles los Proxies de ES6?
¡¡Saludos!!
Be First to Comment