【问题标题】:Is there Proxy-object polyfill available google chrome?是否有 Proxy-object polyfill 可用的谷歌浏览器?
【发布时间】:2014-09-14 10:41:16
【问题描述】:

这甚至可能吗?其他浏览器呢? es6 何时“准备就绪”并推出?

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy

顺便说一句。 https://github.com/tvcutsem/harmony-reflect 代理不适用于当前的 chrome (36.0.n)

【问题讨论】:

    标签: javascript google-chrome proxy polyfills


    【解决方案1】:

    更新:虽然我的回答提供了部分解决方案,但 mailmindlin 的 solution 证明我的主要观点是错误的:您可以Proxy 创建一个 polyfill。

    不,你不能。因为Proxys 依赖于几种语言语法元素的特殊(新)行为——即. 运算符和[index] 运算符——它不能被polyfill 模拟。

    这样做的唯一方法是更改​​您使用的语法。例如,如果您想通过代理将所有字符串属性大写,您可以创建一个“代理”对象,如下所示:

    var object = ...
    var proxy = {
        get: function proxyGet(key) {
            var res = object[key];
            if (typeof res === "string") {
                res = res.toUpperCase();
            }
            return res;
         }
    }
    

    但是,您仍然必须以不同的方式称呼它:

    proxy.get("myVar");
    

    而不是

    object.myVar;
    

    proxy.myVar
    

    这是新的代理语法所支持的。


    注意:您可以几乎创建一个仅适用于方法的 polyfill,方法是枚举对象的函数属性,并在代理对象上为每个属性创建一个代理函数;但是,这不适用于非函数属性,因为您无法动态影响它们的访问方式。

    【讨论】:

    • 您可能还可以控制对已使用 Object.defineProperty 定义的非函数属性的访问,以设置 getter 和 setter。
    • 如果我理解正确,这允许定义在幕后工作的访问器方法,允许使用通常的“点”访问语法?这意味着我完全错了。您为什么不将评论扩展到答案?我会发现它非常有用,OP 也是如此。
    • @mailmindlin 感谢您发布您的答案!我期待在未来看到您对Stack Overflow 的贡献!
    【解决方案2】:

    这是由 Google Chrome 团队创建的: https://github.com/GoogleChrome/proxy-polyfill

    不过,这不是一个完整的实现。

    【讨论】:

      【解决方案3】:

      我创建了 babel 插件,它允许您这样做,但它会带来巨大的性能影响(对于每个属性访问) - 这是更多的教育示例。

      https://github.com/krzkaczor/babel-plugin-proxy

      【讨论】:

        【解决方案4】:

        您可以使用Object.definePropertyObject.observe 来模拟代理。我开始想知道 polyfill 可以支持多少功能,所以我编写了一个实现(你可以在 gist.github.com/mailmindlin/640e9d707ae3bd666d70 看到它)。 我能够模拟 Proxy 的所有不依赖于运算符重载的功能,这在 JavaScript 中是不可能的。

        但是,您可以让getset 和其他一些工作。您可以使用 getter 和 setter 来镜像目标对象的属性:

        for (var property in target)
            Object.defineProperty(proxy, property, {
                get: function() {
                    if ('get' in handler)
                        return handler.get(target, property, proxy);
                    else
                        return target[property];
               },
               set: function(value) {
                   if ('set' in handler)
                       handler.set(target, property, value, proxy);
                   else
                       target[property] = value;
              }});
        

        唯一的问题是 getter 和 setter 只适用于在代理初始化时为目标定义的属性,delete 运算符将不起作用(如果您删除目标上的属性对象,代理仍会将其枚举为属性;如果您删除代理上的属性,则该对象不会发生任何事情。

        要解决这个问题,您可以使用Object.observe,在对任一对象进行任何更改时都会调用它。对caniuse.com 的快速检查表明 Object.observe 在 Chrome 和 Opera 上可用。如果您确实需要在其他浏览器上支持 Proxy,您可以轮询 targetproxy 对象,以检查是否已创建或销毁任何属性:

        var oldKeys = Object.keys(proxy);
        setInterval(function() {
            var keys = Object.keys(proxy);
            for(var i in keys)
                if(!oldKeys.includes(keys[i]))
                    //Trigger code for a new property added
        
            for(var i in oldKeys)
                if(!keys.includes(oldKeys[i]))
                    //trigger code for a deleted property
        
            oldKeys = keys;
        
            //repeat for target object
        }, 100);
        

        如果您迫切需要代理的更多功能,可以尝试覆盖 Object.definePropertyObject.getOwnPropertyDescriptor 等方法,但这可能会导致与其他脚本的兼容性问题,具体取决于您的操作方式。

        简而言之,您可以使用 Proxy 和 polyfill 完成大部分您可能需要的事情。至于谷歌将它添加到他们的浏览器,我不知道。它显然曾经是 V8 引擎的一部分,但由于安全问题(没有人详细说明)而被删除,据我所知 this thread

        【讨论】:

        • 不幸的是,Object.observer 似乎并没有被太多使用,所以它在 Chrome 和 Opera 中被弃用了。 caniuse.com/#search=Proxy 显示,截至 2016 年 8 月,Proxy 可用于所有主要浏览器(占全球用户的 56.54%),而 Object.observe 仅可用于 8.01%(并且正在下降)。
        猜你喜欢
        • 2014-12-03
        • 2011-11-13
        • 2018-04-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-02-12
        • 2012-11-29
        • 2012-07-14
        相关资源
        最近更新 更多