Peter Tseng Peter Tseng - 1 year ago 121
Javascript Question

Is it possible to change a Proxy's target?

I have a class that implements the XMLHttpRequest interface. Depending on the URL passed to

, I can determine whether to use the default XMLHttpRequest or my custom implementation. My idea is to use a proxy to do this:

let xhr = new XHRProxy();'GET', 'http://blah'); // Decide here depending on URL

I did some tests using the ES6 Proxy, which seems promising, but unfortunately the proxy target cannot be modified after constructing the Proxy:

var foo = {
name() {
return "foo";
var bar = {
name() {
return "bar";
var handler = {
get(target, property, receiver) {
if (property === "switchToBar") {
// FIXME: This doesn't work because a Proxy's target is not exposed AFAIK = bar;
return function() {};
} else {
return target[property];
var proxy = new Proxy(foo, handler);
console.log(; // foo
console.log(; // foo :(

I think I can accomplish what I want by not setting a target at all - instead defining all traps to delegate to the desired object - but I'm hoping for a simpler solution.

Answer Source

Here's a go at "defining all traps to delegate to desired object"

(function () {
  let mutableTarget;
  let mutableHandler;

  function setTarget(target) {
    if (!(target instanceof Object)) {
      throw new Error(`Target "${target}" is not an object`);
    mutableTarget = target;

  function setHandler(handler) {
    Object.keys(handler).forEach(key => {
      const value = handler[key];

      if (typeof value !== 'function') {
        throw new Error(`Trap "${key}: ${value}" is not a function`);

      if (!Reflect[key]) {
        throw new Error(`Trap "${key}: ${value}" is not a valid trap`);
    mutableHandler = handler;

  function mutableProxyFactory() {
    setTarget(() => {});

    // Dynamically forward all the traps to the associated methods on the mutable handler
    const handler = new Proxy({}, {
      get(target, property) {
        return (...args) => mutableHandler[property].apply(null, [mutableTarget, ...args.slice(1)]);

    return {
      getTarget() {
        return mutableTarget;
      getHandler() {
        return mutableHandler;
      proxy: new Proxy(mutableTarget, handler)

  window.mutableProxyFactory = mutableProxyFactory;

const { 
} = mutableProxyFactory();

setTarget(() => 0);
console.log(`returns: ${proxy()}`);

setTarget({ val: 1 });
console.log(`val is: ${proxy.val}`);

setTarget({ val: 2 });
console.log(`val is: ${proxy.val}`);

setTarget(() => 3);
console.log(`returns: ${proxy()}`);

I feel like there must be some reason this isn't supported out of the box, but I don't have enough information to comment on that further.

After hacking on this for a while, I've observed a few things. It seems the original target that the proxy constructor is called with is treated as part of the proxy's identity regardless. Setting the original target to a plain object and swapping the target to a function later raises an error, when the proxy is called. There are definitely some rough edges to this, so use with caution.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download