I would like to test if a JavaScript object is a Proxy. The trivial approach
if (obj instanceof Proxy) ...
doesn\'t work here, nor does tra
In my current project I also needed a way of defining if something was already a Proxy, mainly because I didn't want to start a proxy on a proxy. For this I simply added a getter to my handler, which would return true if the requested variable was "__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;
}
Might not be the best solution, but I think it's an elegant solution, which also doesn't pop up when serializing.
I believe I have found a safer way to check if the item is a proxy. This answer was inspired by Xabre's answer.
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
});
}
Essentially what I've done is, instead of adding the __isProxy
field to the target, I added this check: if (property === Symbol.for("__isProxy")) return true;
in the getter of the proxy. This way if you are using a for-in loop or Object.keys
or Object.hasOwnProperty
, __isProxy will not exist.
Unfortunately, even though you can set the value of __isProxy
, you will never be able to retrieve it, due the check on the getter. Therefore you should throw an error when the field gets set.
You could also use a Symbol
to check whether a variable is a Proxy, if you think that its likely you want to use __isProxy
as a different property.
Finally, I also added similar functionality for the target of the proxy, which can also be quite as hard to retrieve.
instanceof Proxy
:I don't recommend it, but If you want to add support for instanceof
, you could do the following before instantiating any Proxies:
(() => {
var proxyInstances = new WeakSet()
// Optionally save the original in global scope:
originalProxy = Proxy
Proxy = new Proxy(Proxy, {
construct(target, args) {
var newProxy = new originalProxy(...args)
proxyInstances.add(newProxy)
return newProxy
},
get(obj, prop) {
if (prop == Symbol.hasInstance) {
return (instance) => {
return proxyInstances.has(instance)
}
}
return Reflect.get(...arguments)
}
})
})()
// Demo:
var a = new Proxy({}, {})
console.log(a instanceof Proxy) // true
delete a
var a = new originalProxy({}, {})
console.log(a instanceof Proxy) // false
delete a
Use window.postMessage() with try-catch
postMessage cannot serialize objects which incompatible with structured clone algorithm, like Proxy.
function isProxy(obj) {
try {
postMessage(obj, "*");
} catch (error) {
return error && error.code === 25; // DATA_CLONE_ERR
}
return false;
}
It is impossible to detect if something is a Proxy
according to the JS language specification.
node does provide a mechanism via native code, but I don't recommend its use - you're not supposed to know if something is a Proxy
.
Other answers that suggest wrapping or shadowing the global Proxy
will not actually work cross-realm (ie, iframes, web workers, node's vm module, wasm, etc).
There are two ways to proxy an object. One is new Proxy
, another is Proxy.revocable
. We may spy them so that proxied object are recorded to a secret list. Then we determine an object is a proxied object by checking if
it exists in the secret list.
To spy functions, we may write wrappers or use the built-in Proxy. The latter means that use Proxy to proxy new Proxy
as well as Proxy.recovable
, here is a fiddle to demo the idea.
To serve the old Proxy API like nodejs-v5.8.0 Proxy, we may apply the same idea by using Proxy.createFunction
to proxy Proxy.create
and Proxy.createFunction
.