Proxies en JavaScript con ES6

Los proxies son otra de las features interesantes que han llegado con ES6, y básicamente su función es la de definir un comportamiento personalizado cada vez que se accede a las propiedades de un objeto.

 

es6 proxy

 

Un Proxy por sí mismo no hace gran cosa, pero podemos definir ‘trampas’ para interceptar las operaciones de bajo nivel con el objeto target u objeto destino, incluidas las llamadas a funciones. Es aquí donde reside la potencia y lo interesante de los proxies.

Sintaxis:

const proxy = new Proxy(target, handler)

Os dejo el link de la lista de los posibles interceptores que podemos utilizar en un Proxy para que investiguéis un poco, ahora veamos en detalle algunos de los más interesantes .

 

get / set

Las ‘trampas’ más comunes serán las que intercepten cuando leemos o escribimos propiedades en el objeto, para ello podemos utilizar una ‘trampa’ get que se activará cada vez que se intente obtener un valor del objeto target, o un set que se activará cada vez que se intente setear una propiedad de nuestro objeto target.

let handler = {
  get (target, key, receiver) {
    console.log(`Get on property "${key}"`)
    return target[key]
  },
  set (target, key, value, receiver) {
    console.log(`Set on property "${key}" with value "${key}"`)
    target[key] = value
    return true
  }
}

let target = {}
let proxy = new Proxy(target, handler)
proxy.foo = 'baz'  // Set on property "foo" with value "baz"
proxy.foo  // Get on property "foo"

Si nos paramos a analizar el código anterior veremos que no tiene mucha ciencia, cada vez que intentemos recuperar el valor de una propiedad o setearlo, la consola nos pintará un mensaje, pero, paremonos un momento a repasar los argumentos que reciben cada uno de estos métodos:

  • target: referencia al objeto que deberá ser interceptado.
  • key: nombre de la propiedad.
  • value: valor para la propiedad.
  • receiver: se trata del objeto al que fue dirigida la asignación inicialmente, normalmente suele ser el propio Proxy. Comentar que este argumento se utiliza muy poco.

 

has

El método has es una trampa para el operador in, que retornará true si la propiedad especificada está en el objeto target.

let pokemon = {
  'Pikachu': '025',
  'Pignite': '499',
  'Boldore': '525'
}

let handler = {
  has (target, key) {
    if (key in target) {
      return true
    } else {
      return false
    }
  }
}

let proxy = new Proxy(pokemon, handler)
'Pikachu' in pokemon  // true
'Kyurem' in pokemon  // false

 

deleteProperty

El método deleteProperty es una trampa para el operador delete, el cual elimina una propiedad de un objeto.

Tomando el ejemplo anterior, implementemos el método deleteProperty en nuestro handler:

let pokemon = {
  'Pikachu': '025',
  'Pignite': '499',
  'Boldore': '525'
}

let handler = {
  deleteProperty (target, key) {
    return true
  }
}

let proxy = new Proxy(pokemon, handler)
delete pokemon['Pikachu']  // true
delete pokemon['Kyurem']  // false
console.log(pokemon)  // Object {Pignite: "499", Boldore: "525"}

Como vemos, la respuesta será true en el caso en el que la propiedad exista en el objeto target y se pueda eliminar. En caso contrario devolverá false.

 

apply

El método apply es una trampa para interceptar llamadas a funciones. A diferencia de los métodos anteriores los cuales reciben un Object como target, este espera recibir una función.

let target = function () { 
  return 'I am the target'
}
let handler = {
  apply (receiver, ...args) {
    return 'I am the proxy'
  }
};

let p = new Proxy(target, handler)
console.log(target())  // I am the target
console.log(p())  // I am the proxy

 

Una de las funcionalidad más interesantes, bajo mi punto de vista, es la capacidad para interceptar llamadas a métodos de objetos. El Dr. Axel Rauschmayer ha escrito al respecto en esta entrada de su blog, así que yo no voy a reinventar la rueda, podéis echarle un vistazo vosotros mismos.

 

En resumen

Los proxies nos permiten modificar el comportamiento de cualquier objeto interceptando las llamadas a sus propiedades y métodos a través de un controlador, y sin duda, las posibilidades que esto nos aporta son muy potentes.

Respecto a la compatibilidad con los diferentes navegadores es bastante buena (y si no, para eso está Babel) así que, ¿a que está esperando para empezar a usarlos?

Hasta la próxima!