es6 javascript ecmascript-6 proxy-classes

javascript - es6 - ¿Cómo probar si un objeto es un Proxy?



javascript proxy get (11)

Me gustaría probar si un objeto JavaScript es un Proxy . El enfoque trivial

if (obj instanceof Proxy) ...

no funciona aquí, ni atraviesa la cadena de prototipos para Proxy.prototype , ya que todas las operaciones relevantes están respaldadas efectivamente por el objetivo subyacente.

¿Es posible probar si un objeto arbitrario es un Proxy?


Crea un nuevo símbolo:

let isProxy = Symbol("isProxy")

Dentro del método get de su controlador proxy, puede verificar si la key es su símbolo y luego return true :

get(target, key) { if (key === isProxy) return true; // normal get handler code here }

Luego puede verificar si un objeto es uno de sus servidores proxy utilizando el siguiente código:

if (myObject[isProxy]) ...


Creo que he encontrado una forma más segura de verificar si el artículo es un proxy. Esta respuesta fue inspirada por la respuesta de Xabre .

function getProxy(target, property) { if (property === Symbol.for("__isProxy")) return true; if (property === Symbol.for("__target")) return target; return target[property]; } function setProxy(target, property, value) { if (property === Symbol.for("__isProxy")) throw new Error("You cannot set the value of ''__isProxy''"); if (property === Symbol.for("__target")) throw new Error("You cannot set the value of ''__target''"); if (target[property !== value]) target[property] = value; return true; } function isProxy(proxy) { return proxy == null ? false : !!proxy[Symbol.for("__isProxy")]; } function getTarget(proxy) { return isProxy(proxy) ? proxy[Symbol.for("__target")] : proxy; } function updateProxy(values, property) { values[property] = new Proxy(getTarget(values[property]), { set: setProxy, get: getProxy }); }

Esencialmente, lo que he hecho es, en lugar de agregar el campo __isProxy al destino, agregué esta verificación: if (property === Symbol.for("__isProxy")) return true; en el captador del proxy. De esta manera, si está utilizando un bucle for-in o Object.keys o Object.hasOwnProperty , __isProxy no existirá.

Desafortunadamente, aunque puede establecer el valor de __isProxy , nunca podrá recuperarlo, debido a la verificación en el getter. Por lo tanto, debe arrojar un error cuando se establece el campo.

También puede usar un Symbol para verificar si una variable es un Proxy, si cree que es probable que quiera usar __isProxy como una propiedad diferente.

Finalmente, también agregué una funcionalidad similar para el objetivo del proxy, que también puede ser tan difícil de recuperar.


De hecho, existe una solución para determinar si el objeto es proxy, que se basa en varios supuestos. En primer lugar, la determinación de proxy se puede resolver fácilmente para el entorno node.js través de extensiones C ++ o una página web privilegiada en el navegador, cuando la página puede iniciar extensiones no seguras. En segundo lugar, Proxy es una funcionalidad relativamente nueva, por lo que no existe en los navegadores antiguos, por lo que la solución solo funciona en los navegadores modernos.

El motor JS no puede clonar funciones (ya que tienen enlaces al contexto de activación y algunas otras razones), pero el objeto Proxy por definición consiste en controladores de envoltura. Entonces, para determinar si el objeto es proxy, es suficiente para iniciar la clonación de objetos forzados. Se puede hacer a través de la función postMessage .

Si el objeto es Proxy, no se podrá copiar aunque no contenga ninguna función. Por ejemplo, Edge y Chrome producen los siguientes errores al intentar publicar el objeto Proxy: [object DOMException]: {code: 25, message: "DataCloneError", name: "DataCloneError"} y no se Failed to execute ''postMessage'' on ''Window'': [object Object] could not be cloned. .



El mejor método que he encontrado es crear un conjunto débil de objetos proxy. Puede hacer esto de forma recursiva cuando construye y verifica sus objetos proxy.

var myProxySet = new WeakSet(); var myObj = new Proxy({},myValidator); myProxySet.add(myObj); if(myProxySet.has(myObj)) { // Working with a proxy object. }


En Node.js 10 puede usar util.types.isProxy .

Por ejemplo:

const target = {}; const proxy = new Proxy(target, {}); util.types.isProxy(target); // Returns false util.types.isProxy(proxy); // Returns true


En mi proyecto actual también necesitaba una forma de definir si algo ya era un Proxy, principalmente porque no quería iniciar un proxy en un proxy. Para esto, simplemente agregué un captador a mi controlador, que devolvería verdadero si la variable solicitada fuera "__Proxy":

function _observe(obj) { if (obj.__isProxy === undefined) { var ret = new Proxy(obj || {}, { set: (target, key, value) => { /// act on the change return true; }, get: (target, key) => { if (key !== "__isProxy") { return target[key]; } return true; } }); return ret; } return obj; }

Puede que no sea la mejor solución, pero creo que es una solución elegante, que tampoco aparece cuando se serializa.


Es imposible detectar si algo es un Proxy según la especificación del lenguaje JS.

El nodo proporciona un mecanismo a través del código nativo, pero no recomiendo su uso; no se supone que sepa si algo es un Proxy .

Otras respuestas que sugieren envolver o sombrear el Proxy global en realidad no funcionarán entre reinos (es decir, iframes, trabajadores web, módulo vm de nodo, wasm, etc.).


Hay dos formas de representar un objeto. Uno es new Proxy , otro es Proxy.revocable . Podemos espiarlos para que el objeto proxy se registre en una lista secreta. Luego determinamos que un objeto es un objeto proxy comprobando si existe en la lista secreta.

Para espiar funciones, podemos escribir envoltorios o usar el Proxy incorporado. Esto último significa que use Proxy para proxy new Proxy así como Proxy.recovable , aquí hay un fiddle para demostrar la idea.

Para servir la antigua API Proxy como nodejs-v5.8.0 Proxy, podemos aplicar la misma idea usando Proxy.createFunction para proxy Proxy.create y Proxy.createFunction .


Matthew Brichacek y David Callanan dan buenas respuestas para el Proxy que creas tú mismo, pero si no es el caso, aquí hay algunas adiciones

Imagine que tiene una función externa que crea Proxy que no puede modificar

const external_script = ()=>{ return new Proxy({a:5},{}) }

Antes de cualquier ejecución de código externo, podemos redefinir el constructor del proxy y usar un WeakSet para almacenar el proxy como lo hace Matthew Brichacek. No uso una clase porque, de lo contrario, Proxy tendrá un prototipo y será detectable que Proxy ha cambiado.

const proxy_set = new WeakSet() window.Proxy = new Proxy(Proxy,{ construct(target, args) { const proxy = new target(...args) proxy_set.add(proxy) return proxy } }) const a = external_script() console.log(proxy_set.has(a)) //true

Mismo método pero con Símbolo como David Callanan

const is_proxy = Symbol(''is_proxy'') const old_Proxy = Proxy const handler = { has (target, key) { return (is_proxy === key) || (key in target) } } window.Proxy = new Proxy(Proxy,{ construct(target, args) { return new old_Proxy(new target(...args), handler) } }) const a = external_script() console.log(is_proxy in a) //true

Creo que el primero es mejor porque solo cambias el constructor mientras que el segundo crea un proxy de un proxy mientras el propósito de la pregunta era evitar esto.

No funciona si el proxy se crea dentro de un iframe porque solo hemos redefinido el proxy para el marco actual.


Parece que no hay una forma estándar, pero para el código privilegiado de Firefox puedes usar

Components.utils.isProxy(object);

Por ejemplo:

Components.utils.isProxy([]); // false Components.utils.isProxy(new Proxy([], {})); // true