javascript - 是否可以更改代理的目标?

标签 javascript xmlhttprequest ecmascript-6

我有一个实现 XMLHttpRequest 接口(interface)的类。根据传递给 open() 的 URL,我可以确定是使用默认的 XMLHttpRequest 还是我的自定义实现。我的想法是使用代理来执行此操作:

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

我使用 ES6 Proxy 做了一些测试,这看起来很有希望,但不幸的是,在构建 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
            receiver.target = bar;
            return function() {};
        } else {
            return target[property];
        }
    }
}
var proxy = new Proxy(foo, handler);
console.log(proxy.name()); // foo
proxy.switchToBar();
console.log(proxy.name()); // foo  :(

我认为我可以通过根本不设置目标来完成我想要的 - 而是定义所有陷阱以委托(delegate)给所需的对象 - 但我希望有一个更简单的解决方案。

最佳答案

这里介绍“定义所有陷阱以委托(delegate)给所需对象”

(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(() => {});
    setHandler(Reflect);

    // 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 {
      setTarget,
      setHandler,
      getTarget() {
        return mutableTarget;
      },
      getHandler() {
        return mutableHandler;
      },
      proxy: new Proxy(mutableTarget, handler)
    };
  }

  window.mutableProxyFactory = mutableProxyFactory;
})();

const { 
  proxy, 
  setTarget 
} = 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()}`);

我觉得一定有某种原因不支持开箱即用,但我没有足够的信息来进一步评论。

在研究了一段时间之后,我观察到了一些事情。无论如何,调用代理构造函数的原始目标似乎都被视为代理身份的一部分。将原始目标设置为普通对象并将目标交换为函数会在调用代理时引发错误。这肯定有一些粗糙的边缘,因此请谨慎使用。

关于javascript - 是否可以更改代理的目标?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38364065/

相关文章:

javascript - 在对象数组中搜索字符串

javascript - 如何使用 loadash/javascript 嵌套多个 groupby

javascript - 消息提示 onsubmit return validate 但表单仍然提交

javascript - Axios 发布表单数据在 native react 中无法正常工作

javascript - Slick.js 不适用于 Polymer 2.0

jquery - 如何使用 jquery 过滤 xml 数据?

javascript - "Access-Control-Allow-Origin"错误,当我有 "Access-Control-Allow-Origin: *"

javascript - 颜色框删除框架箭头导航

javascript - 使用表单提交上传具有相同字段名称的多个文档

javascript - 如何从 $http.get 请求中删除 header 并将 "application/json"和 "text/plain"添加到 "Accept"