Комментарии (2)
🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Как работает eval в JavaScript
Это важный вопрос, потому что 90% разработчиков говорят "никогда не используй eval!", но не все понимают почему. Давайте разберемся.
Что такое eval?
eval - это встроенная функция, которая выполняет JavaScript код из строки:
// Базовое использование
const result = eval('2 + 2'); // 4
console.log(result); // 4
// Выполнение кода
eval('console.log("Hello from eval")'); // Hello from eval
// Создание переменных
eval('var x = 5');
console.log(x); // 5
// Выполнение функций
eval('function greet(name) { return "Hello " + name; }');
console.log(greet('John')); // Hello John
Как eval работает "под капотом"?
// eval выполняет код в текущем контексте (scope)
var globalVar = 'global';
function example() {
var localVar = 'local';
eval('console.log(globalVar)'); // global - доступна
eval('console.log(localVar)'); // local - доступна!
eval('var evalVar = "eval"; console.log(evalVar)'); // eval
}
example();
// Это ключевая фишка eval - он имеет доступ к локальным переменным!
// Обычные функции этого не могут:
function normalFunction() {
var localVar = 'local';
function inner() {
console.log(localVar); // local - работает через closure
}
inner();
}
Различные типы eval
Прямой eval (Direct eval)
// Имеет доступ к локальной области видимости
var x = 1;
function test1() {
var x = 2;
eval('console.log(x)'); // 2 - использует локальный x!
}
test1();
Непрямой eval (Indirect eval)
// Выполняется в глобальном контексте
var x = 1;
function test2() {
var x = 2;
(0, eval)('console.log(x)'); // 1 - использует глобальный x!
// или
const evalFn = eval;
evalFn('console.log(x)'); // 1
}
test2();
// Трюк с (0, eval) часто используется в библиотеках
Почему eval опасен?
Опасность 1: Проблемы безопасности (XSS)
// Пользователь вводит код
const userInput = 'console.log("hack"); fetch("/steal-data")';
// Разработчик делает так (НИКОГДА!):
eval(userInput); // Выполнит вредоносный код!
// Правильно:
const parsed = JSON.parse(userInput);
// или используй более безопасные парсеры
Опасность 2: Производительность
// eval требует интерпретации строки при КАЖДОМ вызове
for (let i = 0; i < 1000000; i++) {
eval('1 + 1'); // Очень медленно!
}
// Правильно:
for (let i = 0; i < 1000000; i++) {
1 + 1; // Быстро, код оптимизируется
}
Опасность 3: Отладка
// eval код не видно в стек-трейсе
eval(`
function buggyFunction() {
throw new Error('Bug');
}
buggyFunction();
`);
// Stack trace будет бесполезен
// К тому же трудно дебажить код, загруженный из строки
Опасность 4: Статический анализ
// Инструменты не могут анализировать код в eval
eval('const x = 5'); // Лinter не знает про x
console.log(x); // Лinter не знает что это существует
// IDE не может помочь с автодополнением
Опасность 5: Непредсказуемость
var y = 'global';
function confusing() {
var y = 'local';
const code = 'y'; // какой y вернет eval?
const result = eval(code); // 'local' или 'global'?
console.log(result); // 'local' (прямой eval)
}
confusing();
// Непредсказуемо и запутанно!
Реальные примеры использования eval (когда это оправдано)
Редко оправданное использование 1: JSON.parse
// СТАРЫЙ способ (eval) - НИКОГДА!
const data = eval('(' + jsonString + ')');
// ПРАВИЛЬНЫЙ способ (всегда):
const data = JSON.parse(jsonString);
// JSON.parse безопаснее и быстрее
Редко оправданное использование 2: Динамические вычисления
// Калькулятор, который парсит математические выражения
// ОЧЕНЬ ПЛОХО:
function calculate(expression) {
return eval(expression); // Опасно!
}
calculate('2 + 2'); // 4
calculate('Math.max(5, 3)'); // 5
// ХОРОШО: используй парсер выражений
import { evaluate } from 'mathjs';
function calculate(expression) {
return evaluate(expression);
}
// или строго контролируй:
function safeCalculate(expression) {
// Проверяй, что это только числа и операторы
if (!/^[0-9+\-*/().,\s]*$/.test(expression)) {
throw new Error('Invalid expression');
}
return eval(expression);
}
Редко оправданное использование 3: Динамические плагины
// Система плагинов, которая загружает код
// ОЧЕНЬ опасно, но если ДОЛЖНО быть:
// 1. Загрузи в Web Worker (изолированный контекст)
// 2. Используй iframe с sandbox
// 3. Используй V8 (Node.js) с изолированным контекстом
// НО НИКОГДА не eval код от пользователей прямо!
// Или используй более безопасные альтернативы:
import JEXL from 'jexl'; // Безопасный парсер выражений
const context = { x: 5, y: 3 };
await JEXL.eval('x + y', context); // 8
Альтернативы eval
Альтернатива 1: Function constructor
// Немного безопаснее, но всё ещё плохо
const fn = new Function('a', 'b', 'return a + b');
fn(2, 3); // 5
// Но:
// - Работает только в глобальном scope
// - Медленно
// - Трудно отлаживать
Альтернатива 2: Парсеры выражений
// Для простых выражений
import { evaluate } from 'mathjs';
evaluate('2 + 3 * 4'); // 14
// Для более сложных
import JEXL from 'jexl';
await JEXL.eval('x > 5 && y < 10', { x: 6, y: 8 }); // true
Альтернатива 3: JSON
// Если нужно передать данные, используй JSON
const jsonString = '{"x": 5, "y": 3}';
const data = JSON.parse(jsonString); // Безопасно!
Альтернатива 4: Web Workers
// Для выполнения непроверенного кода в изолированном контексте
const worker = new Worker('worker.js');
worker.postMessage({ code: userCode });
worker.onmessage = (e) => {
console.log(e.data);
};
// В worker.js:
self.onmessage = (e) => {
try {
const result = eval(e.data.code); // eval в Worker - безопаснее
self.postMessage(result);
} catch (error) {
self.postMessage({ error: error.message });
}
};
Альтернатива 5: iframe с sandbox
<!-- Самая безопасная изоляция -->
<iframe
sandbox="sandbox"
srcdoc="<script>/* пользовательский код */</script>"
></iframe>
Когда eval всё ещё встречается
// 1. Старый код (jQuery era)
// 2. Некоторые шаблонизаторы (template literals лучше)
// 3. Некоторые библиотеки (обычно можно найти замену)
// 4. Инструменты отладки (browser DevTools используют eval)
Правило thumb
// НИКОГДА не используй eval, если:
// ✓ Есть альтернатива
// ✓ Нужна безопасность
// ✓ Нужна производительность
// ✓ Нужна отладка
// ✓ Нужна читаемость
// Используй eval ТОЛЬКО если:
// - Ты в изолированном контексте (Worker, iframe)
// - Ты 100% контролируешь код
// - Нет другого выхода
// - Ты знаешь что делаешь
Практический пример (неправильно vs правильно)
// НЕПРАВИЛЬНО - опасная система шаблонов
function renderTemplate(template, data) {
// Заменяем {{x}} на значение x
const code = template.replace(/{{(\w+)}}/g, (match, key) => {
return `'${data[key]}'`;
});
return eval('`' + code + '`');
}
renderTemplate('Hello {{name}}', { name: 'John' }); // OK
renderTemplate('Hello {{name}}; console.log("hacked") }}', {}); // Опасно!
// ПРАВИЛЬНО - безопасная система шаблонов
function renderTemplate(template, data) {
return template.replace(/{{(\w+)}}/g, (match, key) => {
return data[key] || '';
});
}
renderTemplate('Hello {{name}}', { name: 'John' }); // OK
renderTemplate('Hello {{name}}; console.log("safe") }}', {}); // Безопасно!
Итого
evalв JavaScript:
- Выполняет строку как код в текущем контексте
- Имеет доступ к локальным переменным
- Очень медленно - код интерпретируется при каждом вызове
- Опасен для безопасности - может выполнить вредоносный код
- Затрудняет отладку - код невидим в стек-трейсах
- Ломает статический анализ - IDE не может помочь
- НИКОГДА не используй без очень хорошей причины
Практический совет: если ты думаешь использовать eval, сначала подумай 3 раза. Потом подумай еще раз. Потом используй альтернативу.