动态(匿名)函数中的 TypeScript 调用函数

TypeScript call function in dynamic (anonymous) function

我正在尝试在 TypeScript 中创建一个动态函数,它调用一个已经存在的函数,例如:

let dynamicFunction = new Function("existingFunction(\"asdf\");");

function existingFunction(name: string) {
    console.log(name);
}

在 chrome 中调试 dynamicFunction 时如下所示:

(function() {
existingFunction("asdf");
})

当我尝试执行 dynamicFunction 时,它显示 "Uncaught ReferenceError: existingFunction is not defined",这并不奇怪,因为它是不同的范围,但我如何才能在 dynamicFunction 中实际调用 exisitingFunction?

如有任何帮助,我们将不胜感激!

编辑:

更准确地说:我有一个包含一个模块的打字稿文件。 该模块导出一个函数,该函数应该 return 创建的动态函数。 然后,创建的 dynamicFunction 用于另一个实际包含 exisitingFunction 的模块。

之所以选择这种方法,是因为我需要将给定的字符串转换为可执行条件,该条件将被执行多次。

例如:将字符串 "VALUE==1" 转换为:

function () {
    return exisitingFunction("VALUE") == 1;
}

它应该是什么样子的一个简短示例:

parser.ts:

export module Parser {
   export function getFunction(expression: string) {
      // Calculating condition...
      let condition = "existingFunction(\"VALUE\") == 1;"
      return new Function(condition);
   }
}

condition.ts:

import { Parser } from "./parser";
class Condition {
    // getting the DynamicFunction
    private _dynamicFunction = Parser.getFunction("VALUE==1");

    someFunctionInsideCondition() {
       // Calling the DynamicFunction
       this._dynamicFunction();
    }
}

// Maybe this function should be somewhere else?
function existingFunction(name: string) {
    console.log(name);

    return 1;
}

我希望这能更好地解释我的问题。

来自Function documentation

Functions created with the Function constructor do not create closures to their creation contexts; they always are created in the global scope. When running them, they will only be able to access their own local variables and global ones, not the ones from the scope in which the Function constructor was called. This is different from using eval with code for a function expression.

所以你必须将 existingFunction 作为参数传递或在全局 space 中定义它。

试试

var existingFunction = function(name: string) {
    console.log(name);
}

另请查看 eval,这将使您能够访问当前范围 ...

--- 更新

问题更新后,考虑到您关于出于安全考虑不想使用 eval 的评论(我完全同意)

问题是在生成的函数范围内,thisundefined。让你的 existingFunction 成为全局范围的一部分已经不是一个好主意,而且在 Typescript 和模块架构之间似乎根本不可能。

那么为什么不将上下文传递给生成的函数呢?

这将允许您控制应用程序向生成的函数公开多少内容,同时允许它访问外部方法。

大致如下:

class Parser {
    static getFunction(expression) {
        let condition = new Function("context", "context.existingFunction(\"VALUE\") == 1;");
        return condition;
    }
}

class Condition {
    constructor() {
        this._dynamicFunction = Parser.getFunction("VALUE==1");
    }

    someFunctionInsideCondition() {
        // Calling the DynamicFunction
        this._dynamicFunction(this);
    }

    existingFunction(name) {
        console.log("hello " + name);

        return 1;
    };
}



let c = new Condition();
c.someFunctionInsideCondition();

当然,您的 context 可以是一个不同的对象,而不是 this,您可以在其中保留所有实用程序函数。

I had to donwpile (compile it down, my own word) to es2015 to make the example run here, but I made it originally in Typescript and works fine

我会跳过 new Function 的用法,而是按如下方式进行。

parser.ts 文件将包含以下内容:

export class FunctionGenerator {
    constructor(private fn: Function) {}

    makeFunction(args: string): Function {
        const [variable, val] = args.split("==");
        return () => this.fn(variable) == val;
    }
}

这基本上是一个允许创建一系列函数的工厂,这些函数调用创建工厂时传递的函数。然后,您可以使用 makeFunction 进行您要执行的特定检查。 (请注意,我在你的问题中使用了 == 。我更喜欢使用 === 除非有理由反对它。)

然后可以这样使用:

import * as parser from "./parser";

let vars = {};

// This is a simulation of your funciton. It just plucks values from `vars`.
function existingFunction(name: string) {
    return vars[name];
}

function resetVars() {
   vars = {
    "VALUE": 1,
    "FOO": 2,
    "BAR": 3,
   };
}

function test(gen) {
    const fn1 = gen.makeFunction("VALUE==1");
    console.log(fn1(), "should be true");

    const fn2 = gen.makeFunction("BAR==3");
    console.log(fn2(), "should be true");

    vars["BAR"] = 7;
    // Call the same function again, but with a new value in `vars`.
    console.log(fn2(), "should be false");

    const fn3 = gen.makeFunction("BAR==1000");
    console.log(fn3(), "should be false");
}

resetVars();
const gen = new parser.FunctionGenerator(existingFunction);
test(gen);