Одно отличие от eval
заключается в том, что литералы шаблонов анализируются во время компиляции, а аргумент eval
анализируется только во время выполнения, когда выполняется eval
.
С этим связано то, что eval
может получить динамически созданный аргумент, в то время как литерал шаблона является ... литералом: он не может быть сохранен как переменная шаблона, что вы могли бы строить динамически, перемещаться и, в конечном итоге, анализировать: нет типа данных «переменная шаблона». Функция тега на самом деле получает в качестве аргумента не переменную шаблона, а ее проанализированные компоненты, которые известны во время компиляции.
Некоторые примеры
С eval
у вас может быть такая ситуация:
var code = prompt('enter some evil code');
eval(code);
Но это невозможно с литералами шаблонов:
var literal = prompt('enter some evil template literal');
tag literal; // there is no data type or syntax for this.
`${literal}`; // and this just gives you the entered string.
Что возможно, это:
var str = prompt('enter some string');
tag`${str}`;
Но это не приводит к выполнению нежелательного кода, по крайней мере, не хуже этого:
var str = prompt('enter some string');
myfunc(str);
Любые вызовы функций должны быть уже закодированы буквально в литерале шаблона. Значения строковых переменных не могут этого изменить. Литерал шаблона не может вызвать переменную функцию. Этот:
`${func(str)}`;
... вызовет func
и только эту функцию. Выбирается программистом.
Довольно злой шаблонный литерал
Сказав это, это все еще возможно:
var func = prompt ("enter some evil function name (suggestion: 'alert')");
var param = prompt ("now provide an argument for " + func);
`${window[func](param)}`;
Но видно, что программа охотно открывает возможность выполнения любой функции над глобальным объектом. Тогда действительно вы приближаетесь к злу eval
.
Обратите внимание, что тот же эффект достигается с помощью:
window[name](param);
Самый злой шаблонный литерал
Как прокомментировано, вы также можете сделать этот шаблон литералом:
`eval(str)`;
... и, таким образом, плохая часть заключается не столько в литерале шаблона, сколько в универсальном вызове функции, который вы разработали для его включения. Для этого нужны не шаблонные литералы или eval
, а плохой программист ;-)
На примере
Вы привели такой пример:
let ii = 1;
function counter() {
return ii++;
}
console.log(`${counter()}, ${ii++}, ${counter()}`);
Это выполняет вашу функцию counter
, но отличие от eval
заключается в том, что строковый литерал уже существовал во время разработки и не мог быть создан во время выполнения. Этот код предназначен для увеличения вашего счетчика и по существу не отличается от:
console.log(counter() + ', ' + (ii++) + ', ' + counter());
Время компиляции
Чтобы подчеркнуть разницу между синтаксическим анализом во время компиляции и выполнения, обратите внимание, что вы не можете запускать код с литералом шаблона, который не имеет допустимого синтаксиса.
Сравните эти два скрипта:
alert('press OK');
eval('alert("hello)');
а также:
alert('press OK');
`${alert("hello)}`;
Обратите внимание на синтаксическую ошибку. Первый сценарий заметит синтаксическую ошибку только во время выполнения, когда будет проанализирован аргумент eval
, в то время как второй сценарий даже не запустится и немедленно выдаст синтаксическую ошибку.
Точнее, eval
выполняет новый скрипт с собственными фазами компиляции и запуска. Литерал шаблона анализируется/компилируется, как и любой другой код.
person
trincot
schedule
15.05.2016
eval()
, поскольку все, что они делают (обычно), это оценивают выражения и приводят результат к строке. - person Pointy   schedule 16.05.2016eval
запускает произвольные строки как код. Я не думаю, что вы можете сделать это с литералами шаблонов. Это совершенно разные вещи. - person Oriol   schedule 16.05.2016eval
... - person Leonid Beschastny   schedule 16.05.2016console.log(counter() + ', ' + ii++ + ', ' + counter())
, который является точным эквивалентом. Вы по-прежнему считаете это небезопасным? - person Felix Kling   schedule 16.05.2016