Если вы хотите замок некоторые переменные при преобразовании функции в строку, вы должны передать, что переменные вдоль строковой функции.
Это может быть реализовано, как это (написано с типами - машинопись обозначения)
const prepareForEval =
(fn: Function, variablesToLock: { [varName: string]: any }): string => {
const stringifiedVariables = Object.keys(variablesToLock)
.map(varName => `var ${varName}=${JSON.stringify(variablesToLock[varName])};`);
return stringifiedVariables.join("") + fn.toString();
}
Затем используйте его как этот
const stringifiedFunction = prepareForEval(someFunction, { x: x, y: y })
// you can even simplify declaration of object, in ES6 you simply write
const stringifiedFunction = prepareForEval(someFunction, { x, y })
// all variables you write into curly braces will be stringified
// and therefor "locked" in time you call prepareForEval()
Любой eval
объявим строковой переменные и Funtion в месте, где он был выполнен. Это может быть проблемой, вы можете переопределить какую-либо переменную в новое неизвестное значение, вы должны знать имя стробированной функции, чтобы иметь возможность вызвать ее, или она может вызвать ошибку, если вы повторно указали уже объявленную переменную const
.
Чтобы преодолеть эту проблему, вы должны реализовать строковую функцию, как мгновенный выполняется анонимная функция со своей собственной сферой, как
const prepareForEval =
(fn: Function, variablesToLock: { [varName: string]: any }): string => {
const stringifiedVariables = Object.keys(variablesToLock)
.map(varName => `var ${varName}=${JSON.stringify(variablesToLock[varName])};`);
return `
var ${fn.name} = (function() {
${stringifiedVariables.join("")}
return ${fn.toString()};
)();
`;
}
этой модификация будет объявлять функции и переменные в отдельном объеме, а затем он присвоит эту функцию до fn.name
постоянный. Переменные не будут обменивать область, где вы eval
, она просто объявит новую переменную fn.name
, и эта новая переменная будет настроена на десериализованную функцию.
Как 'fn.toString() => \' (... args) => {const x = $ {JSON.stringify (window.x)} ; return $ {this.toString()} (... args); } \ ';'? Или если вы действительно хотите захватить возвращаемое значение функции: 'fn.toString =() => \'() => $ {JSON.stringify (this())} \ ';'. –
Сколько усилий вы хотите вложить в это? Легко, если вы знаете, какие переменные захватывать. Это также легко, если вы просто захватили вывод (если функция не принимает никаких входных данных и не имеет побочных эффектов, то этого достаточно). Если вы действительно хотите запустить функцию, фиксируя значения ее свободных переменных, но вы не знаете имя свободных переменных, вам нужно сначала найти имена. Вы можете сделать это, проанализировав строковое представление функции и используя инструмент https://github.com/estools/escope, чтобы найти свободные переменные. –
@FelixKling в какой-то момент будет стоить приличного количества усилий. Пока мы можем дублировать переменные в рамках отдельных функций - это не очень хороший подход, но он делает то, что нам нужно. Очевидно, если есть лучший метод, мы бы хотели его использовать! – maxcountryman