Это возможно , но единственный способ сделать это, о котором я могу думать, это Плохая идея ™ в большинстве случаев: eval
или ее близкая кузина new Function
:
const xyz = () => console.log("xyz");
const str = "xyz";
(0,eval)(str + "()");
new Function(str + "()")();
Проблема с eval
(прямым или косвенным) и new Function
заключается в том, что они запускают произвольный код из строки, запуская полный JavaScript парсер для этого. Неправильное использование открывает дверь к атакам XSS или проблемам с неэффективным кодом (хотя парсеры удивительно быстры в наши дни).
Для тех, кто не не знаю (я думаю, что OP знает): глобальные const
, let
и class
привязки не добавляются как свойства к глобальному объекту, как глобальные var
и function
привязки. Вот почему window[str]();
не будет работать.
О
(0,eval)(str + "()");
выше: это косвенное значение . Он работает, отделяя поиск идентификатора eval
от вызова, что разрывает специальную ссылку eval
с локальной областью видимости. В этом случае он использует оператор запятой, чтобы сделать это. Подробности:
Вы, вероятно, знаете, что eval
имеет доступ к локальной области (и всем, содержащим области), поэтому, например, это работает:
function foo() {
const answer = 42;
eval("console.log(answer);");
}
foo();
Код в eval
может видеть answer
, поскольку он имеет доступ к области, в которую вы позвонили eval
.
Чтобы попытаться ограничить Сила eval
немного, вы можете отключить его доступ к локальной области и заставить его запускать свой код в глобальной области вместо использования eval
косвенно . Например, если вы поместите его в переменную:
function foo() {
const answer = 42;
const e = eval;
e("console.log(answer);"); // Fails with ReferenceError
}
foo();
Отделяя поиск идентификатора eval
от вызова функции, к которой он относится, вы разрываете специальную ссылку, которую он имеет, с локальной областью действия.
Оператор запятой является одним из наиболее необычных операторов JavaScript: он вычисляет свой левый операнд, отбрасывает результат, оценивает свой правый операнд и принимает это значение как результат выражения запятой:
function foo() {
console.log("foo ran and returned 1");
return 1;
}
function bar() {
console.log("bar ran and returned 2");
return 2;
}
const x = (foo(), bar());
console.log(`x = ${x}`);
Использование (0, eval)(str)
отделяет поиск идентификатора eval
от вызова функции, точно так же, как присвоение его e
, как было сделано выше. 0
вычисляется, отбрасывается, затем eval
вычисляется, что приводит к ссылке на функцию, и эта ссылка на функцию является результатом выражения запятой; тогда мы используем его для eval
str
.