【问题标题】:TypeScript call function in dynamic (anonymous) function动态(匿名)函数中的 TypeScript 调用函数
【发布时间】:2016-12-21 11:24:12
【问题描述】:

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

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

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

在 chrome dynamicFunction 中调试时看起来像这样:

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

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

任何帮助将不胜感激!

编辑:

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

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

例如:将字符串“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);
   }
}

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

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

【问题讨论】:

  • 我不明白你到底想做什么,但也许 let dynamicFunction = existingFunction("asdf"); 是你想要的。

标签: javascript typescript dynamic-function


【解决方案1】:

来自Function documentation

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

因此您必须将existingFunction 作为参数传递或在全局空间中定义它。

试试

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,您可以在其中保留所有实用程序功能。

我必须 donwpile(编译下来,我自己的话)到 es2015 以使示例在此处运行,但我最初是在 Typescript 中制作的并且工作正常

【讨论】:

  • 谢谢。这解释了为什么我无法访问“existingFunction”,但这并不能真正解决我的问题。也许看看我的编辑。我更准确地解释了我的问题。
  • 我认为这可能是因为模块。今晚晚些时候我会看看。一般来说,我认为你可能会更幸运地返回一个字符串,然后使用 eval 来执行它
  • 是的,带有格式化字符串的 eval 可以工作,但由于我正在处理敏感数据,我宁愿不使用 eval。
  • 非常感谢!我刚刚在自己的项目中尝试过,现在一切正常。真的让我很烦恼,原来它会这么简单。
【解决方案2】:

我会跳过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);

【讨论】:

  • 如果语句总是那么简单,那就行了。问题是,这些语句与 && 或 || 结合使用会变得非常复杂。当然还有大括号和其他函数(例如 getCurrentDate、乘法/除法、加法/减法)但还是谢谢你!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-11
  • 2013-07-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多