How to get the target of a JavaScript Proxy?

24,404

Solution 1

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.

Solution 2

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!

Solution 3

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:

  • avoids property name conflicts by using a Symbol
  • covers all get-scenarios by using Reflect.get instead of target[property]
  • WARNING: be careful about prototype-inheritance - in case your proxy ends up being used as a prototype the not_itself_a_proxy[IDENTITY] call will not return not_itself_a_proxy but the "identity" of the prototype!

Solution 4

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.

Solution 5

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__);
Share:
24,404
Adam
Author by

Adam

Updated on July 09, 2022

Comments

  • Adam
    Adam almost 2 years
    function createProxy() {
        const myArray = [Math.random(), Math.random()];
        return new Proxy(myArray, {});
    }
    
    const myProxy = createProxy();
    

    How to access the target (which is myArray) of myProxy here?

    I've tried many ways. Was googled many blog posts, but found no way to get the target :(