动态(匿名)函数

时间:2016-12-21 11:24:13

标签: javascript typescript dynamic-function

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

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

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

虽然chrome dynamicFunction中的调试如下所示:

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

当我尝试执行dynamicFunction时,它表示" Uncaught ReferenceError:existingFunction未定义",这并不奇怪,因为它是一个不同的范围,但我怎么能在dynamicFunction中实际调用exisitingFunction?

非常感谢任何帮助!

修改

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

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

例如:convert string" 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;
}

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

2 个答案:

答案 0 :(得分: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中制作并且工作正常

答案 1 :(得分:0)

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