JavaScript - 行为类似于原始的代理对象

JavaScript - proxy object to behave like primitive

提问人:Tibi Neagu 提问时间:3/20/2020 更新时间:3/20/2020 访问量:355

问:

我正在尝试构建一个系统,该系统在加载库之前“缓存”对库的调用。

这类似于 Google Analytics(分析)的“设置”代码对变量所做的操作 - 它被初始化为一个数组,该数组“缓存”对真实分析端点的调用,直到库加载完毕。当它这样做时,它会读取并重播呼叫。_gaqga.js_gaq

我们之所以决定这样做,是因为我们的遗留代码包含对特定库的大量调用,这些库在 中同步加载。这大大增加了首次内容绘制的时间,因为评估和执行了大量的 JS。<head>

但是,代码中有太多的地方需要更改(包装在侦听器中),因此我们决定尝试使用解决方法。'DOMContentLoaded'

我们决定尝试使用 to catch 对库方法的调用,并在准备就绪后重播它们:Proxy

// Original code:
var ourLib = new OurLib({ ... });

// Throughout the site, calls such as:
var res1 = ourLib.doThis();
var res2 = ourLib.getThat(3);

下面是我们新代码正在执行的操作的“简化”版本:

// New code:
var ourLib = new Proxy({
    calls: [],
}, {
    get(target, prop) {
        if (prop in target) {
            return Reflect.get(...arguments);
        }

        const callref = { prop, args: [], placeholder };
        target.calls.push(callref);

        return function(...args) {
            const placeholder = MakeResultPlaceholder(...);

            callref.args = args;
            callref.placeholder = placeholder;

            return placeholder;
        };
    },
});

// Throughout the site, calls continue as before, except now they're 'stored' in `calls`
var res1 = ourLib.doThis();
var res2 = ourLib.getThat(3);

// Much later, the original lib is loaded, and 
var ourRealLib = new OurLib({ ... });
__playbackCalls(ourLib.calls, ourRealLib);

// Replace the proxy with the real thing
ourLib = ourRealLib;

运行上述操作后,属性将如下所示:calls

[
    {
        prop: 'doThis',
        args: [],
        reference: ResultPlaceholder
    },
    {
        prop: 'getThat',
        args: [3],
        reference: ResultPlaceholder
    }
]

该函数遍历数组和每个方法,并存储在每个对象中。__playbackCallscallsapplyourRealLibargs

calls.forEach(({ prop, args, reference }) => {
    reference._value = ourRealLib[prop].apply(ourRealLib, args);
});

当需要使用代理调用的结果时,问题就来了。现在,正如你所看到的,调用返回一个对象(它本身就是另一个代理)。这些占位符保存在“播放”期间填充的属性。placeholder_value

所以问题来了:

  • 比方说,要返回一个 .ourLib.getThat()number
  • 在第一次“运行”期间,由于整个代理的事情,会指向一个对象:res1placeholderProxy { _value: undefined }
  • 真正的库被加载,“播放”完成,返回,所以会ourRealLib.getThat(3)23res1Proxy { _value: 23 }
  • 我可以做任何事情来用作数字吗?像这样:res1
console.log(res1 * 2); // 46
JavaScript ecmascript-6 javascript 对象 元编程

评论

1赞 Jonas Wilms 3/20/2020
不。你不能。另外,我怀疑你真的想要那个。不过,您的示例将起作用。res1 = { getValue() { this._value; } };
1赞 Tibi Neagu 3/20/2020
@JonasWilms 还是 ?getValuevalueOf
1赞 Jonas Wilms 3/20/2020
valueOf,为时已晚......
0赞 Tibi Neagu 3/20/2020
@JonasWilms建议似乎对我有用。如果是一个实际的对象,而不仅仅是基元,它甚至可以工作。你为什么说你怀疑我真的想要那个?这样使用它有什么缺点吗?valueOf_value
1赞 Bergi 3/20/2020
缓存调用的方法仅适用于 Google Analytics,因为众所周知,它们不会返回任何内容。

答: 暂无答案