eval
это зло в JavaScript! Страница MDN eval гласит:
устарелый
Эта функция устарела. Хотя он все еще поддерживается браузерами, его использование не рекомендуется в новых проектах. Старайтесь избегать его использования.
eval
выполняет строку, содержащую код, например
eval("var x = 'Hello from eval!';"); console.log(x);
eval
поднимает несколько вопросов:
- Безопасность: ваша строка может быть введена другими командами сторонними скриптами или пользовательским вводом.
- Отладка: сложно отладить ошибки — у вас нет номеров строк или явных точек сбоя.
- Оптимизация: интерпретатор JavaScript не обязательно может предварительно скомпилировать код, потому что он может измениться. Хотя интерпретаторы становятся все более эффективными, они почти наверняка будут работать медленнее, чем собственный код.
К сожалению, eval
очень мощный, и менее опытным разработчикам легко злоупотребить командой.
Несмотря на предупреждения, eval
прежнему работает — даже в строгом режиме — но вы обычно можете его избежать. В прошлом он в основном использовался для JSON.parse
строк JSON, но теперь у нас есть более безопасный метод JSON.parse
.
Однако, что если у нас есть имя функции в строке, например
// function we want to run var fnstring = "runMe"; function runMe() { // do stuff }
Как мы выполняем runMe()
без использования eval
? Недавно я столкнулся с такой ситуацией при использовании API истории HTML5 ; метод pushState не позволит вам сохранить прямую ссылку на функцию, поэтому вам нужно определить ее имя в виде строки. Вы также можете столкнуться с аналогичными проблемами, используя Web Workers или любой другой API, где объекты сериализуются.
Самое простое и безопасное решение без выполнения — это ряд условий, например
// function we want to run var fnstring = "runMe"; switch (fnstring) { case "functionX": functionX(); break; case "functionY": functionY(); break; case "functionZ": functionZ(); break; case "runMe": runMe(); break; }
Это безопасно, но довольно неэффективно и больно писать, если у вас есть десятки возможных вызовов функций.
Лучшее решение — использовать объект window
который ссылается на текущее окно и все элементы в нем. Мы можем проверить, доступен ли fnstring
как объект в window
и запустить его, если это функция, например
// function we want to run var fnstring = "runMe"; // find object var fn = window[fnstring]; // is object a function? if (typeof fn === "function") fn();
При необходимости вы можете выполнить другие проверки, чтобы убедиться, что функция имеет ожидаемое имя.
Что если функция, которую мы хотим вызвать, имеет параметры — возможно, хранящиеся в массиве? Нет проблем; мы просто используем метод apply
:
// function name and parameters to pass var fnstring = "runMe"; var fnparams = [1, 2, 3]; // find object var fn = window[fnstring]; // is object a function? if (typeof fn === "function") fn.apply(null, fnparams);
Так что это еще одна причина отказаться от использования eval
. В качестве бонуса, это решение безопаснее, менее подвержено ошибкам, проще в отладке и, как правило, выполняется быстрее. Я надеюсь, что это помогает.