我正在尝试在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;
}
我希望这能更好地解释我的问题。
答案 0 :(得分:1)
使用Function构造函数创建的函数不会为其创建上下文创建闭包;它们总是在全球范围内创建。运行它们时,它们只能访问自己的局部变量和全局变量,而不能访问调用Function构造函数的范围。这与使用eval和函数表达式的代码不同。
因此您必须将existingFunction
作为参数传递或在全局空间中定义它。
尝试
var existingFunction = function(name: string) {
console.log(name);
}
另请查看eval
,它可以让您访问当前范围......
---更新
问题更新后,考虑到您因安全问题而不想使用eval的评论(我完全同意)
问题在于,在生成的函数范围内,this
为undefined
。使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);