2016-12-21 3 views
0

Я пытаюсь создать динамическую функцию в машинописном, которая вызывает уже существующую функцию, как:машинописи вызова в (анонимных) функциях динамического

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

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

При отладке в хромированной dynamicFunction выглядит следующим образом:

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

Когда я пытаюсь выполнить dynamicFunction, он говорит: «Uncaught ReferenceError: existingFunction не определен», что неудивительно, потому что это другая область, но как я могу называть exisitingFunction внутри dynamicFunction?

Любая помощь была бы принята с благодарностью!

Edit:

быть более точным: я получил машинопись файл, который содержит один модуль. Этот модуль экспортирует функцию, которая должна вернуть созданную динамическую функцию. Созданная динамическая функция затем используется в другом модуле, который фактически содержит 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); 
    } 
} 

состоянии .:

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 надеюсь, это объясняет мою проблему немного лучше.

+0

Я не понимаю, что именно вам 'пытаюсь сделать, но, может быть, 'let dynamicFunction = existingFunction (" asdf ");' это то, что вы хотите. –

ответ

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 в качестве аргумента или определить его в глобальном пространстве.

попробовать с

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

Также посмотрите на eval, который даст вам доступ к текущей области ...

--- Обновление

После обновления вопроса и с учетом вашего комментарий о том, что вы не хотите использовать eval из-за проблем с безопасностью (с которыми я полностью согласен)

Проблема в том, что в сгенерированном fu nction, this - undefined. Создание вашей части existingFunction в глобальной области уже плохой идеей, и между архитектурой TypScript и модулей вообще не представляется возможным.

Так почему бы не передать контекст сгенерированной функции?

Это позволит вам контролировать, какая часть вашего приложения должна отображаться в сгенерированной функции, предоставляя ему доступ к внешним методам.

Что-то вдоль линий:

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

+0

Спасибо. Это объясняет, почему я не могу получить доступ к «existingFunction», но это не позволяет решить мою проблему. Может быть, посмотрите на мое редактирование. Я более точно объяснил свою проблему. – Sarah

+0

Я думаю, это может быть из-за модулей. Сегодня вечером я посмотрю. В общем, я думаю, что у вас может быть больше удачи в возвращении только строки, а затем с помощью eval для ее выполнения. – alebianco

+0

да, eval с форматированной строкой может работать, но поскольку я имею дело с конфиденциальными данными, я бы предпочел не использовать eval. – Sarah

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

Это будет работать, если утверждения всегда будут такими простыми. Проблема в том, что эти утверждения могут быть очень сложными в сочетании с && или || и, конечно, фигурные скобки и другие функции (например, getCurrentDate, умножение/разделение, добавление/вычитание) Но спасибо вам! – Sarah