Как запустить функцию глобальной константы из переменной в браузере - PullRequest
3 голосов
/ 07 января 2020

Я могу получить доступ и запустить любую функцию, находящуюся в окне Object, используя имя String. например,

function abc() {
  console.log("abc");
}
var str = "abc";
window[str](); // abc

но я хочу знать, возможно ли как-то запустить функцию, объявленную с ключевым словом const .

const xyz = () => console.log("xyz");
const str = "xyz";
window[str](); // TypeError: window.xyz is not a function

1 Ответ

3 голосов
/ 07 января 2020

Это возможно , но единственный способ сделать это, о котором я могу думать, это Плохая идея ™ в большинстве случаев: 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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...