Reputation: 5233
How to access the target (which is myArray
) of myProxy
here?
function createProxy() {
const myArray = [Math.random(), Math.random()];
return new Proxy(myArray, {});
}
const myProxy = createProxy();
I'd like to have a getProxyTarget
function that would return the original object without modifying any other part of the code:
let original;
function createProxy() {
const myArray = [Math.random(), Math.random()];
original = myArray;
return new Proxy(myArray, {});
}
const myProxy = createProxy();
function getProxyTarget(proxy){ /* ... your code */ }
console.log(getProxyTarget(myProxy) === original) // should be true
Upvotes: 88
Views: 88444
Reputation: 1147
Lodash cloneDeep works wonders - const targetCopy = _.cloneDeep(myProxy)
. It roughly does the same as const targetCopy = JSON.stringify(JSON.parse(myProxy))
- but in a neater way. Partly because it doesn't go through the redundant step of converting to a string and back; partly because it has great Typescript support, so TS knows what cloneDeep returns.
Upvotes: -1
Reputation: 858
I found a great way to get the original target by defining the getPrototypeOf
handler:
function createProxy() {
const myArray = [Math.random(), Math.random()];
return new Proxy(myArray, {
getPrototypeOf(target) {
return target;
}
});
}
const myProxy = createProxy();
const target = Object.getPrototypeOf(myProxy); // will get the original array
Upvotes: 3
Reputation: 417
I found Array.from seems work.
function createProxy() {
const myArray = [Math.random(), Math.random()];
return new Proxy(myArray, {});
}
const myProxy = createProxy();
const l=Array.from(myProxy)
console.assert(l.every(it=>!isNaN(it)));
Upvotes: -1
Reputation: 1139
If you are using Vue 3 and dealing with Proxies, Vue provides some methods to help with this:
import { isProxy, toRaw } from 'vue';
Using these, you can check if an object is a proxy with isProxy
, for example:
isProxy(reactiveObjectOrArray) ? 'yup' : 'nope'
And you can extract the raw data using toRaw
:
const rawObjectOrArray = toRaw(reactiveObjectOrArray)
More info on toRaw and isProxy
Upvotes: 85
Reputation: 11
Use a private Symbol
to trap a property. Then give a public function to test if the object returns true
for this Symbol
.
var sym_Test = Symbol('test')
let proxyHandler = {
get: function(pValues:any, prop:any, receiver:any){
if(prop == sym_Test)
return true;
return getValue(pValues, prop)
},
}
export function IsMyProxy(some:any){
return some[sym_Test]
}
Upvotes: -1
Reputation: 521
Like the other answers already said a proxy get trap can be an elegant solution.
const IDENTITY = Symbol('proxy_target_identity')
const handler = {
get: (target, property, receiver) => {
if (property === IDENTITY) {
return target
}
return Reflect.get(target, property, receiver)
}
}
function createProxy() {
const myArray = [Math.random(), Math.random()];
return new Proxy(myArray, handler);
}
const myProxy = createProxy();
const orignal_target = myProxy[IDENTITY]
This code sample should be quite robust as it:
Symbol
Reflect.get
instead of target[property]
not_itself_a_proxy[IDENTITY]
call will not return not_itself_a_proxy
but the "identity" of the prototype!Upvotes: 14
Reputation: 1229
I find that (using Vue.js where sometimes Proxy objects are involved, e.g. when watching a component prop) I can obtain the target both if it is an Object and if it is an Array using JSON.stringify
:
let myTarget = JSON.parse(JSON.stringify(myProxy))
This approach works also with Array targets, whereas Object.assign({}, myProxy)
works only if the target is an Object.
But I am very new to JavaScript proxies and my knowledge is limited. I may not understand the limitations and caveats of this approach. Nevertheless, maybe it helps someone!
Upvotes: 28
Reputation: 727
The other answers gave some good solutions. Here is @Yuci's answer distilled down for classes, in which case, it's as simple as defining an instance variable of some special name. The Proxy get function returns it, and so does the underlying target.
class Foo {
constructor() {
this.__target__ = this;
return new Proxy(this, {
get: function (target, name) {
if (name in target) return target[name];
// your code here
}
});
}
}
let foo = new Foo();
let target = foo.__target__;
console.log('proxied Foo', foo);
console.log('recovered target', target, target.__target__.__target__);
Upvotes: 4
Reputation: 30109
How about adding the following get trap:
const handler = {
get: (target, property, receiver) => {
if (property === 'myTarget') {
return target
}
return target[property]
}
}
const myArray = [Math.random(), Math.random()];
function createProxy() {
// const myArray = [Math.random(), Math.random()];
return new Proxy(myArray, handler);
}
const myProxy = createProxy();
And you can get the target of the proxy by myProxy.myTarget
:
console.log(myProxy.myTarget) // [0.22089416118932403, 0.08429264462405173]
console.log(myArray === myProxy.myTarget) // true
Upvotes: 3
Reputation: 89
There is a clever way to do this - You can add a get trap to the proxy and have it return the target conditionally. Like so..
let resolveMode = false; // Switch that controls if getter returns target or prop.
function resolve(obj) {
resolveMode = true; // Turn on our switch
let target = obj.anything; // This gets the target not the prop!
resolveMode = false; // Turn off the switch for the getter to behave normally
return target; // Return what we got!
}
function createProxy() {
const myArray = [Math.random(), Math.random()];
return new Proxy(myArray, {
get: function(target, prop) {
if (resolveMode) return target; // This is where the magic happens!
else return target[prop]; // This is normal behavior..
}
});
}
const myProxy = createProxy();
let target = resolve(myProxy);
Remember that the more lines of code you add to traps, the slower the object's performance gets. Hope this helps.
Upvotes: 8
Reputation: 1302
You can if the target is an object.
You will have to create a function in target to retrieve it, that's all.
Example:
class AnyClass {
constructor() {
this.target = this;
return new Proxy(this, this);
}
get(obj, prop) {
if (prop in obj)
return this[prop];
// your stuff here
}
getTarget() {
return this.target;
}
}
And then when you call:
let sample = new AnyClass;
console.log(sample.getTarget());
Will return you the target as you expect :)
Upvotes: 2
Reputation: 1816
As the proxy contain an object you can also do
Object.keys( my_proxy )
And then it become easy to retrieve thing such as Object.keys( my_proxy ).length
Upvotes: -2
Reputation: 2847
You can make a copy of the data returned by the proxy using Object.assign()
:
const target_copy = Object.assign({}, my_proxy);
This will work for all enumerable own properties existing on the proxy/target.
Upvotes: 53