Как можно динамически создать функцию с кодом из произвольной строки js
Перейти к содержимому

Как можно динамически создать функцию с кодом из произвольной строки js

  • автор:

Is there a way to create a function from a string with javascript?

If this is the string, I want a function that’s called fnc. And fnc(); pops alert screen.

eval(«alert(1);») doesnt solve my problem.

9 Answers 9

A better way to create a function from a string is by using Function :

This has as advantage / disadvantage that variables in the current scope (if not global) do not apply to the newly constructed function.

Passing arguments is possible too:

I added a jsperf test for 4 different ways to create a function from string :

Using RegExp with Function class

var func = «function (a, b) < return a + b; >«.parseFunction();

Using Function class with «return»

var func = new Function(«return » + «function (a, b) < return a + b; >«)();

Using official Function constructor

var func = new Function(«a», «b», «return a + b;»);

eval(«var func = function (a, b) < return a + b; >;»);

2 result samples: enter image description here enter image description here

phnah's user avatar

You’re pretty close.

Yes, using Function is a great solution but we can go a bit further and prepare universal parser that parse string and convert it to real JavaScript function.

examples of usage:

Mr. Pumpkin's user avatar

Dynamic function names in JavaScript

Using Function

Using eval

Using sjsClass

Example

This technique may be ultimately equivalent to the eval method, but I wanted to add it, as it might be useful for some.

This is functionally like adding this <script> element to the end of your document, e.g.:

David Newberry's user avatar

Use the new Function() with a return inside and execute it immediately.

An example with dynamic arguments:

If you have a function expression that is in string form and you want to make it a function, then you need to include a return statement in the string you pass to new Function .

Динамическое создание функции из строки JavaScript

JavaScript предоставляет мощные инструменты для работы с функциями, включая возможность создавать новые функции во время выполнения программы. Это можно сделать с помощью функции new Function() .

Базовый принцип работы функции new Function()

Функция new Function() принимает два аргумента: строку, содержащую список параметров функции, и строку с телом функции. Обе строки могут быть произвольными и задаваться динамически во время выполнения программы. Вот пример использования этой функции:

Создание функции из произвольной строки кода

Если у вас есть произвольная строка кода JavaScript, вы можете использовать new Function() для создания функции из этого кода. Вот как это можно сделать:

Как видите, это очень мощный инструмент, который позволяет вам динамически создавать и выполнять функции JavaScript на основе произвольных строк кода. Однако с большой мощью идут и большие ответственности. Помните о безопасности и не исполняйте произвольный код, который может быть вредоносным.

Синтаксис "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]] , ссылающийся на глобальное лексическое окружение, а не на родительское. Поэтому они не могут использовать внешние локальные переменные. Но это очень хорошо, потому что страхует нас от ошибок. Переданные явно параметры – гораздо лучшее архитектурное решение, которое не вызывает проблем у минификаторов.

The "new Function" syntax

There’s one more way to create a function. It’s rarely used, but sometimes there’s no alternative.

Syntax

The syntax for creating a function:

The function is created with the arguments arg1. argN and the given functionBody .

It’s easier to understand by looking at an example. Here’s a function with two arguments:

And here there’s a function without arguments, with only the function body:

The major difference from other ways we’ve seen is that the function is created literally from a string, that is passed at run time.

All previous declarations required us, programmers, to write the function code in the script.

But new Function allows to turn any string into a function. For example, we can receive a new function from a server and then execute it:

It is used in very specific cases, like when we receive code from a server, or to dynamically compile a function from a template, in complex web-applications.

Closure

Usually, a function remembers where it was born in the special property [[Environment]] . It references the Lexical Environment from where it’s created (we covered that in the chapter Variable scope, closure).

But when a function is created using new Function , its [[Environment]] is set to reference not the current Lexical Environment, but the global one.

So, such function doesn’t have access to outer variables, only to the global ones.

Compare it with the regular behavior:

This special feature of new Function looks strange, but appears very useful in practice.

Imagine that we must create a function from a string. The code of that function is not known at the time of writing the script (that’s why we don’t use regular functions), but will be known in the process of execution. We may receive it from the server or from another source.

Our new function needs to interact with the main script.

What if it could access the outer variables?

The problem is that before JavaScript is published to production, it’s compressed using a minifier – a special program that shrinks code by removing extra comments, spaces and – what’s important, renames local variables into shorter ones.

For instance, if a function has let userName , minifier replaces it with let a (or another letter if this one is occupied), and does it everywhere. That’s usually a safe thing to do, because the variable is local, nothing outside the function can access it. And inside the function, minifier replaces every mention of it. Minifiers are smart, they analyze the code structure, so they don’t break anything. They’re not just a dumb find-and-replace.

So if new Function had access to outer variables, it would be unable to find renamed userName .

If new Function had access to outer variables, it would have problems with minifiers.

Besides, such code would be architecturally bad and prone to errors.

To pass something to a function, created as new Function , we should use its arguments.

Summary

For historical reasons, arguments can also be given as a comma-separated list.

These three declarations mean the same:

Functions created with new Function , have [[Environment]] referencing the global Lexical Environment, not the outer one. Hence, they cannot use outer variables. But that’s actually good, because it insures us from errors. Passing parameters explicitly is a much better method architecturally and causes no problems with minifiers.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *