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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/41261676/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-21 04:06:17  来源:igfitidea点击:

TypeScript call function in dynamic (anonymous) function

javascripttypescriptdynamic-function

提问by Sarah

I am trying to create a dynamic function in TypeScript which calls an already existing function like:

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

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

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

While debugging in chrome dynamicFunction looks like this:

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

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

When I try to execute dynamicFunction, it says "Uncaught ReferenceError: existingFunction is not defined", which is no surprise because it's a different scope, but how can I actually call exisitingFunction inside dynamicFunction?

当我尝试执行 dynamicFunction 时,它说“未捕获的 ReferenceError:existingFunction 未定义”,这并不奇怪,因为它的作用域不同,但是我如何在 dynamicFunction 中实际调用 exisitingFunction 呢?

Any help would be greatly appreciated!

任何帮助将不胜感激!

Edit:

编辑:

to be more precise: I've got a typescript file which contains one module. This module exports a function which should return the created dynamic function. The created dynamicFunction is then used in another module which actually contains the exisitingFunction.

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

I've chosen this approach because I need to convert a given string to an executable condition, which will be executed many times.

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

For example: convert string "VALUE==1" to:

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

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

A short example of how it should look like:

其外观的简短示例:

parser.ts:

解析器.ts:

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

condition.ts:

条件.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;
}

I hope this explains my problem a little bit better.

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

采纳答案by alebianco

From the 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.

使用 Function 构造函数创建的函数不会为其创建上下文创建闭包;它们总是在全局范围内创建。运行它们时,它们只能访问自己的局部变量和全局变量,而不能访问调用 Function 构造函数的范围内的变量。这与将 eval 与函数表达式的代码一起使用不同。

so you'll have to pass existingFunctionas an argument or define it in the global space.

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

try with

尝试

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

Also have a look at evalwhich will give you access to the current scope ...

也看看eval哪个会让你访问当前范围......

--- Update

- - 更新

After the question update and considering your comment about not wanting to use eval because of security concerns (with which i totally agree)

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

The problem is that in the generated function's scope, thisis undefined. Making your existingFunctionpart of the global scope is already a bad idea and between Typescript and the modules architecture doesn't seem possible at all.

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

So why not passing a context to the generated function?

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

This will allow you to control how much of your application to expose to the generated function, while giving it access to external methods.

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

Something along the lines of:

类似的东西:

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();

Of course your contextcan be a different object instead of this, where you keep all your utility functions.

当然,您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

我不得不donwpile(编译下来,我自己的字),以ES2015,使这里的例子运行,但我在打字稿原本由它和正常工作

回答by Louis

I would skip the usage of new Functionand instead do it as follows.

我会跳过使用,new Function而是按如下方式执行。

The parser.tsfile would contain this:

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

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

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

This is basically a factory that allows creating a series of functions that call the function passed when the factory is created. You can then use makeFunctionfor the specific checks you want to perform. (Note that I used ==like in your question. I much prefer using ===unless there's a reason against it.)

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

It can then be used like this:

然后可以像这样使用它:

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);