Синтаксис "new Function"
Существует ещё один вариант объявлять функции. Он используется крайне редко, но иногда другого решения не найти.
Синтаксис
Синтаксис для объявления функции:
Функция создаётся с заданными аргументами arg1. argN и телом functionBody .
Это проще понять на конкретном примере. Здесь объявлена функция с двумя аргументами:
А вот функция без аргументов, в этом случае достаточно указать только тело:
Главное отличие от других способов объявления функции, которые были рассмотрены ранее, заключается в том, что функция создаётся полностью «на лету» из строки, переданной во время выполнения.
Все предыдущие объявления требовали от нас, программистов, писать объявление функции в скрипте.
Но new Function позволяет превратить любую строку в функцию. Например, можно получить новую функцию с сервера и затем выполнить её:
Это используется в очень специфических случаях, например, когда мы получаем код с сервера для динамической компиляции функции из шаблона, в сложных веб-приложениях.
Замыкание
Обычно функция запоминает, где родилась, в специальном свойстве [[Environment]] . Это ссылка на лексическое окружение (Lexical Environment), в котором она создана (мы разбирали это в главе Замыкание).
Но когда функция создаётся с использованием new Function , в её [[Environment]] записывается ссылка не на внешнее лексическое окружение, в котором она была создана, а на глобальное. Поэтому такая функция имеет доступ только к глобальным переменным.
Сравним это с обычным объявлением:
Эта особенность new Function выглядит странно, но оказывается очень полезной на практике.
Представьте, что нужно создать функцию из строки. Код этой функции неизвестен во время написания скрипта (поэтому не используем обычные функции), а будет определён только в процессе выполнения. Мы можем получить код с сервера или с другого ресурса.
Наша новая функция должна взаимодействовать с основным скриптом.
Что если бы она имела доступ к внешним переменным?
Проблема в том, что перед отправкой JavaScript-кода на реальные работающие проекты код сжимается с помощью минификатора – специальной программы, которая уменьшает размер кода, удаляя комментарии, лишние пробелы, и, что самое главное, локальным переменным даются укороченные имена.
Например, если в функции объявляется переменная let userName , то минификатор изменяет её на let a (или другую букву, если она не занята) и изменяет её везде. Обычно так делать безопасно, потому что переменная является локальной, и никто снаружи не имеет к ней доступ. И внутри функции минификатор заменяет каждое её упоминание. Минификаторы достаточно умные. Они не просто осуществляют «тупой» поиск-замену, они анализируют структуру кода, и поэтому ничего не ломается.
Так что если бы даже new Function и имела доступ к внешним переменным, она не смогла бы найти переименованную userName .
Если бы new Function имела доступ к внешним переменным, при этом были бы проблемы с минификаторами.
Кроме того, такой код был бы архитектурно хуже и более подвержен ошибкам.
Чтобы передать что-то в функцию, созданную как new Function , можно использовать её аргументы.
Итого
По историческим причинам аргументы также могут быть объявлены через запятую в одной строке.
Эти 3 объявления ниже эквивалентны:
Функции, объявленные через new Function , имеют [[Environment]] , ссылающийся на глобальное лексическое окружение, а не на родительское. Поэтому они не могут использовать внешние локальные переменные. Но это очень хорошо, потому что страхует нас от ошибок. Переданные явно параметры – гораздо лучшее архитектурное решение, которое не вызывает проблем у минификаторов.
Запуск функции по значению переменной
Когда-то встречал функцию, но забыл, чтобы по значению элемента вызвать одноимённую функцию, не используя switch-case.
Например, a=»add_New_User» или a=»Delete_User» и есть одноимённые функции.
Как их запустить, в зависимости от значения переменной а ?
![]()
Итак, этим ответом я постараюсь наконец исчерпать данную тему, которая постоянно всплывает на (ru)SO
#0. Eval
Метод eval() выполняет JavaScript код, представленный строкой.
Из определения понятно, что его использование крайне просто.
Касательно поставленной задачи это будет выглядеть так:
Важным отличием eval() от иных подходов является то, что выражение, переданное в качестве строки, может ссылаться на текущий контекст:
С использованием, думаю, все понятно.
Однако каждый из нас не один раз уже видел высказывания в духе:
eval() (читать как evil)
eval() — зло!
И далее по списку.
Почему о данной функции бытует такое мнение?
eval() — опасная функция, которая выполняет код, проходящий со всеми привилегиями вызывателя. Если вы запускаете eval() со строкой, на которую могут влиять злоумышленники, то вы можете запустить вредоносный код на устройство пользователя с правами вашей веб-страницы/расширения.
Так что использовать данный метод для серьезных целей не стоит.
#1. Function
Когда речь заходит об eval() , не обойдется и без упоминания о new Function()
Конструктор Function создаёт новый объект Function. В JavaScript каждая функция является объектом Function.
Стоит отметить следующие важные отличия от прошлого подхода:
-
В отличие от eval() , при помощи new Function() мы не просто исполняем код из строки, а мы создаем из него полноценную функцию, аналогичную по свойствам тем, что мы определилили через function() < >(так как глобальный объект Function наследует некоторые методы и свойства через цепочку прототипов объекта Function.prototype ), которая может принимать входные параметры, а также может быть переиспользована
В отличие от eval() , функции, созданные с помощью new Function() , не могут ссылаться на область видимости, в которой они были созданы, так как при вызове они имеют доступ только к глобальным и своим внутренним переменным!
В отличие от eval() , возвращается не последнее вычисленное в теле функции выражение, а то, которое было явно передано с помощью оператора return (ну, или undefined . В общем, поведение обычной функции, так как это она и есть ¯\_(ツ)_/¯)
new Function([arg1[, arg2[, . argN]],] functionBody)
С теорией, думаю, ясно: конструктор new Function() , в который были переданы имена формальных аргументов и обязательный параметр — строковое представление тела метода, создает нам, собственно, функцию
Касательно поставленной задачи:
Думаю, принцип использования понятен.
К слову, new Function() считается более безопасным вариантом, чем eval() , но не стоит забывать, что потенциальный злоумышленник, который имеет доступ к строке, передающейся в качества тела функции, до сих пор может влиять на исполняемый в результате такого построения код
#2. Получение доступа к объекту, как к свойству контейнера с помощью скобочной нотации
Думаю, все мы знаем, что к свойству объекта можно обратиться несколькими путями.
Простенький пример:
Как можно применить это касательно поставленной задачи?
Я уже затронул это в сниппете выше, но давайте рассмотрим это дело чуть подробнее:
Данный метод можно считать одним из наиболее правильных при решении поставленной задачи, ведь скобочная и точечная нотация взаимозаменяемы и их поведение полностью документировано, а также при помощи скобочной нотации злоумышленнику вряд ли удастся запустить какой-либо (свой) вредоносный код
В комментариях упоминалось, что может потребоваться запустить функцию, путь к которой описан следующим образом: myObj.method.myFunc .
Ответ прост: разделим строку по точке и пройдем весь этот путь, описанный точечной нотацией, с помощью скобочной:
Дешево, сердито и надежно!
#3. Создание «словаря»
Еще одним неплохим вариантом может явиться способ, идея которого уже представлена на текущий момент в ответе участника @qwabra:
Суть заключается в том, что Вам необходимо создать некоторый объект-«словарь», в который Вы сможете добавлять функции, а после — вызывать их по имени.
Для примера набросал такой код:
Данная конструкция позволяет добавлять функции, вызывать их по имени (можно даже с параметрами), а также — удалять из хранилища.
Итоги
В данном ответе я постарался рассмотреть наиболее распространенные на практике способы вызова функций (местами — не только), имея в наличии лишь строку с их названием.
Прошу обратить Ваше внимание на то, что расположены они в порядке возрастания валидности их использования. Начиная с нежелательного eval() и заканчивая реализацией своей структуры под необходимые нужды.
Вопрос, конечно, касательно рекомендаций может быть спорным, ибо на вкус и цвет, как говорится.
Если Вы считаете, что мой ответ ненароком обошел стороной какой-то очень хороший метод решения указанной проблемы — пишите в комментариях, с радостью дополню ответ!
Как создать функцию из строки в JavaScript?
Задача состоит в том, чтобы создать функцию из строки, заданной в формате функции. Вот несколько методов, обсуждаемых с помощью JavaScript.
Подход 1:
- Используйте конструктор Function (), чтобы создать функцию из строки.
- Он принимает любое количество аргументов (в виде строки). Последний должен быть телом функции.
- В этом примере передается только тело функции, которая возвращает значение.
Пример 1: В этом примере используется подход, описанный выше
create a function from a string in JavaScript
< body style = «text-align:center;» id = «body» >
< h1 style = «color:green;» >
style undefined spaces»> font-weight: bold;»>
< button onclick = «GFG_Fun()» >
style undefined spaces»> font-size: 20px;
var up = document.getElementById(‘GFG_UP’);
var down = document.getElementById(‘GFG_DOWN’);
var func = ‘return «This is return value»;’;
«Click on the button to create «+
«function from string.< br >FUNCTION — ‘»
// Till this point we can use ‘func’ as function.
var func2 = Function(func);
// Now ‘func’ can be used as function.
Выход:
- Прежде чем нажать на кнопку:

- После нажатия на кнопку:

Подход 2:
- Используйте метод eval () для создания функции из строки.
- Он принимает функцию в виде строки и преобразует ее в функцию JavaScript.
- В этом примере он принимает 2 аргумента и возвращает сумму обоих чисел.
Пример 2: В этом примере используется подход, описанный выше.
create a function from a string in JavaScript
< body style = «text-align:center;»
< h1 style = «color:green;» >
style undefined spaces»> font-weight: bold;»>
< button onclick = «GFG_Fun()» >
style undefined spaces»> font-size: 20px;
var up = document.getElementById(‘GFG_UP’);
var down = document.getElementById(‘GFG_DOWN’);
var str = «var func = function (a, b) < return a + b; >;»;
«Click on the button to create «+
«function from string.< br >FUNCTION — ‘» + str + «‘»;
// Till this point we can use ‘func’ as function.
// converting the string to function.
down.innerHTML = func(2, 5);
Выход:
- Прежде чем нажать на кнопку:

- После нажатия на кнопку:
