如何测试对象是否是代理?

GOT*_*O 0 35 javascript proxy-classes ecmascript-6

我想测试JavaScript对象是否是代理.琐碎的方法

if (obj instanceof Proxy) ...
Run Code Online (Sandbox Code Playgroud)

在这里不起作用,也没有遍历原型链Proxy.prototype,因为所有相关操作都得到了底层目标的有效支持.

是否可以测试任意对象是否是代理?

Xab*_*bre 23

在我当前的项目中,我还需要一种方法来定义某些东西是否已经是代理,主要是因为我不想在代理上启动代理.为此我只是在我的处理程序中添加了一个getter,如果请求的变量是"__Proxy",它将返回true:

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;
}
Run Code Online (Sandbox Code Playgroud)

可能不是最好的解决方案,但我认为这是一个优雅的解决方案,在序列化时也不会弹出.

  • 太棒了,我正在使用这种方法,但有一点点扭曲:const IS_PROXY = Symbol("is-proxy"); ...... if(!obj [IS_PROXY]) (3认同)
  • @MatthewJoelRodríguezLlanos 只需确保符号存储在某个闭包中,因为 `Symbol("is-proxy") !== Symbol("is-proxy")`,或者您使用 `Symbol.for` (2认同)

小智 13

来自http://www.2ality.com/2014/12/es6-proxies.html:

无法确定对象是否是代理(透明虚拟化).

  • 我不会链接一篇以"*此博客文章已过时*"开头的文章:-)然而,http://exploringjs.com/es6/ch_proxies.html表示完全相同 (13认同)
  • @BrassApparatus实际上,事实证明他的评论和我的回答都是错误的,详见[这里](http://exploringjs.com/es6/ch_proxies.html#_pitfall-not-all-objects-can-be-wrapped -transparently逐代理). (2认同)

小智 12

在Node.js 10中,您可以使用util.types.isProxy.

例如:

const target = {};
const proxy = new Proxy(target, {});
util.types.isProxy(target);  // Returns false
util.types.isProxy(proxy);  // Returns true
Run Code Online (Sandbox Code Playgroud)


Vla*_*ost 11

事实上,有一种解决方法可以确定对象是否为代理,这是基于几个假设。首先,node.js当页面可以启动不安全的扩展时,可以通过C++扩展或浏览器中的特权网页轻松解决环境的代理确定。其次,代理是相对较新的功能,因此在旧浏览器中不存在 - 因此解决方案仅适用于现代浏览器。

JS 引擎不能克隆函数(因为它们绑定到激活上下文和其他一些原因),但是根据定义,代理对象由包装器处理程序组成。所以要判断对象是否是代理,启动强制对象克隆就足够了。可以通过postMessage函数完成。

如果 object 是 Proxy,即使它不包含任何函数,它也会复制失败。例如,Edge 和 Chrome 在尝试发布 Proxy 对象时会产生以下错误:[object DOMException]: {code: 25, message: "DataCloneError", name: "DataCloneError"}Failed to execute 'postMessage' on 'Window': [object Object] could not be cloned.

  • 有趣的。我想知道是否有一种方法可以使此方法也适用于包含函数、DOM 元素和其他不可克隆内容的对象。 (2认同)
  • +1 用于在许多情况下找到一个真正的解决方案。结果证明,以同样的方式,代理的 Event 对象不能被调度(即,`dispatchEvent`)并且代理的 DOM 元素不能附加到 DOM。也可能有其他独特的(如音频上下文节点)。 (2认同)

Dav*_*nan 8

创建一个新符号:

let isProxy = Symbol("isProxy")
Run Code Online (Sandbox Code Playgroud)

get代理处理程序的方法中,您可以检查它是否key是您的符号,然后return true:

get(target, key)
{
    if (key === isProxy)
        return true;

    // normal get handler code here
}
Run Code Online (Sandbox Code Playgroud)

然后,您可以使用以下代码检查对象是否是您的代理之一:

if (myObject[isProxy]) ...
Run Code Online (Sandbox Code Playgroud)

  • 有趣的!仅供其他人注意,只有当您控制代理获取陷阱时,这才有效。否则,如果您不拥有该对象,这将不起作用。 (3认同)

Eyl*_*tan 8

使用 window.postMessage() 和 try-catch 来获取提示

postMessage无法序列化与结构化克隆算法不兼容的对象,例如代理。

function shouldBeCloneable(o) {
    const type = typeof o;
    return (
        type === "undefined" ||
        o === null ||
        type === "boolean" ||
        type === "number" ||
        type === "string" ||
        o instanceof Date ||
        o instanceof RegExp ||
        o instanceof Blob ||
        o instanceof File ||
        o instanceof FileList ||
        o instanceof ArrayBuffer ||
        o instanceof ImageData ||
        o instanceof ImageBitmap ||
        o instanceof Array ||
        o instanceof Map ||
        o instanceof Set
    );
}

function isCloneable(obj) {
    try {
        postMessage(obj, "*");
    } catch (error) {
        if (error?.code === 25) return false; // DATA_CLONE_ERR
    }

    return true;
}

function isProxy(obj){
    const _shouldBeCloneable = shouldBeCloneable(obj);
    const _isCloneable = isCloneable(obj);

    if(_isCloneable) return false;
    if(!_shouldBeCloneable) return "maybe";
    
    return _shouldBeCloneable && !_isCloneable;
}

console.log("proxied {}", isProxy(new Proxy({},{})));
console.log("{}", isProxy({}));

console.log("proxied []", isProxy(new Proxy([],{})));
console.log("[]", isProxy([]));

console.log("proxied function", isProxy(new Proxy(()=>{},{})));
console.log("function", isProxy(()=>{}));

console.log("proxied Map", isProxy(new Proxy(new Map(),{})));
console.log("new Map()", isProxy(new Map()));

class A{};
console.log("proxied class", isProxy(new Proxy(A,{})));
console.log("class", isProxy(A));

console.log("proxied class instance", isProxy(new Proxy(new A(),{})));
console.log("class instance", isProxy(new A()));
Run Code Online (Sandbox Code Playgroud)

  • 这仅告诉您该对象是否不可克隆,对吧?因此,这个非代理从您的函数返回 true:`isProxy({a:()=>{}})`。它应该被称为“isNotCloneable”。 (2认同)

adj*_*nks 8

添加“支持” instanceof Proxy

我不推荐它,但是如果您想添加对 的支持instanceof,您可以在实例化任何代理之前执行以下操作:

(() => {
  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
Run Code Online (Sandbox Code Playgroud)

  • Yo dawg,听说你喜欢代理,所以我把代理放在你的代理中,这样你制作代理后就可以识别代理了。 (12认同)

小智 7

我发现的最好方法是创建一组弱代理对象。您可以在构建和检查代理对象时递归地执行此操作。

    var myProxySet = new WeakSet();
    var myObj = new Proxy({},myValidator);
    myProxySet.add(myObj);

    if(myProxySet.has(myObj)) {
        // Working with a proxy object.
    }
Run Code Online (Sandbox Code Playgroud)


Ori*_*iol 6

似乎没有标准方法,但是对于 Firefox 特权代码,您可以使用

Components.utils.isProxy(object);
Run Code Online (Sandbox Code Playgroud)

例如:

Components.utils.isProxy([]); // false
Components.utils.isProxy(new Proxy([], {})); // true
Run Code Online (Sandbox Code Playgroud)