首页 > 解决方案 > 为元数据分配和查询 Javascript 箭头函数

问题描述

问题比较简单。我们需要为函数注入一个参数,然后简单地从函数体中提取该参数。我将在打字稿中呈现大纲......

abstract class Puzzle {

    abstract assign(param, fn): any;

    abstract getAssignedValue(): any;

    async test() {

        const wrapped = this.assign(222, async () => {
            return 555 + this.getAssignedValue();
        });

        console.log("Expecting", await wrapped(), "to be", 777);
    }
}

让我们设置场景:

找到我在下面介绍的更优雅的解决方案会很棒。

编辑

好的,我们似乎找到了一个受 zone.js 启发的好的可靠解决方案。那里解决了相同类型的问题,解决方法是重写一些系统级原语的含义,例如 SetTimeout 和 Promise。上面唯一令人头疼的是 async 语句,这意味着函数的主体可以有效地重新排序。异步最终是由 Promise 触发的,所以你必须用上下文感知的东西来覆盖你的 Promise。它涉及很多,而且因为我的用例不在浏览器甚至节点之外,所以我不会让你厌烦细节。对于大多数遇到此类问题的人来说——只需使用 zone.js。

标签: javascripttypescript

解决方案


哈克解决方案 1

我们实际上有一个有效的实现。这是一个非常痛苦的 hack,但证明这应该是可能的。不知何故。也许甚至有一个超级简单的解决方案我只是因为我已经盯着这个太久而错过了。

class HackySolution extends Puzzle {

    private readonly repo = {};

    assign(param: any, fn) {

        // code is a random field for repo. It must also be a valid JS fn name.
        const code = 'd' + Math.floor(Math.random() * 1000001);
        // Store the parameter with this code.    
        this.repo[code] = param;

        // Create a function that has code as part of the name.
        const name = `FN_TOKEN_${code}_END_TOKEN`;
        const wrapper = new Function(`return function ${name}(){ return this(); }`)();

        // Proceed with normal invocation, sending fn as the this argument.
        return () => wrapper.call(fn);
    }

    getAssignedValue() {
        // Comb through the stack trace for our FN_TOKEN / END_TOKEN pair, and extract the code.
        const regex = /FN_TOKEN_(.*)_END_TOKEN/gm;
        const code = regexGetFirstGroup(regex, new Error().stack);
        return this.repo[code];
    }
}

因此,我们解决方案中的想法是检查 的堆栈跟踪new Error().stack,并将我们可以提取的东西包装为令牌,然后我们将其放入回购中。哈基?非常hacky。

笔记

测试表明这实际上是相当可行的,但需要比我们拥有的更现代的执行环境——即 ES2017+。


推荐阅读