Являются ли eval() и new Function() одинаковыми?
Эти две функции делают то же самое за кулисами? (в функциях с одним оператором)
var evaluate = function(string) {
return eval('(' + string + ')');
}
var func = function(string) {
return (new Function( 'return (' + string + ')' )());
}
console.log(evaluate('2 + 1'));
console.log(func('2 + 1'));
6 ответов
Нет, они не одинаковы.
eval()
оценивает строку как выражение JavaScript в текущей области выполнения и может обращаться к локальным переменным.new Function()
анализирует код JavaScript, хранящийся в строке, в объект функции, который затем может быть вызван. Он не может получить доступ к локальным переменным, потому что код работает в отдельной области видимости.
Рассмотрим этот код:
function test1() {
var a = 11;
eval('(a = 22)');
alert(a); // alerts 22
}
Если new Function('return (a = 22);')()
были использованы локальные переменные a
сохранит свою ценность. Тем не менее, некоторые программисты на JavaScript, такие как Дуглас Крокфорд, считают, что ни один из них не должен использоваться, если в этом нет абсолютной необходимости, и оценивать / использовать Function
Конструктор ненадежных данных небезопасен и неразумен.
new Function
создает функцию, которую можно использовать повторно eval
просто выполняет заданную строку и возвращает результат последнего оператора. Ваш вопрос введен в заблуждение, когда вы попытались создать функцию-оболочку, которая использует функцию для эмуляции eval.
Правда ли, что они разделяют некоторый код за кулисами? Да, очень вероятно. Точно такой же код? Нет конечно
Для забавы, вот моя собственная несовершенная реализация, использующая eval для создания функции. Надеюсь, это проливает свет на разницу!
function makeFunction() {
var params = [];
for (var i = 0; i < arguments.length - 1; i++) {
params.push(arguments[i]);
}
var code = arguments[arguments.length - 1];
// Creates the anonymous function to be returned
// The following line doesn't work in IE
// return eval('(function (' + params.join(',')+ '){' + code + '})');
// This does though
return eval('[function (' + params.join(',')+ '){' + code + '}][0]');
}
Самое большое различие между этой и новой функцией заключается в том, что она не имеет лексической области действия. Так что у него не будет доступа к переменным замыкания, а у меня будет.
Нет.
В вашем обновлении звонки evaluate
а также func
произвести тот же результат. Но они определенно не "делают то же самое за кулисами". func
Функция создает новую функцию, но затем немедленно выполняет ее, тогда как evaluate
Функция просто выполняет код на месте.
Из оригинального вопроса:
var evaluate = function(string) {
return eval(string);
}
var func = function(string) {
return (new Function( 'return (' + string + ')' )());
}
Это даст вам очень разные результаты:
evaluate('0) + (4');
func('0) + (4');
Просто хочу указать на некоторый синтаксис, используемый в примерах, здесь и что это значит:
var func = function(string) {
return (new Function( 'return (' + string + ')' )());
}
обратите внимание, что функция (...)() имеет в конце "()". Этот синтаксис заставит func выполнить новую функцию и вернуть строку, а не функцию, которая возвращает строку, но если вы используете следующее:
var func = function(string) {
return (new Function( 'return (' + string + ')' ));
}
Теперь func вернет функцию, которая возвращает строку.
Если вы имеете в виду, даст ли он те же результаты, то да... но просто eval (иначе говоря, "оценить эту строку JavaScript") будет намного проще.
РЕДАКТИРОВАТЬ ниже:
Это все равно что сказать... эти две математические задачи одинаковы:
1 + 1
1 + 1 + 1 - 1 + 1 - 1 * 1/1
В этом примере результаты одинаковы, да. Оба выполняют переданное вами выражение. Это то, что делает их такими опасными.
Но они делают разные вещи за кулисами. Один с участием new Function()
За кулисами из предоставленного вами кода создается анонимная функция, которая выполняется при ее вызове.
JavaScript, который вы передаете ему, технически не выполняется, пока вы не вызовете анонимную функцию. Это в отличие от eval()
который выполняет код сразу и не генерирует функцию на его основе.
Функция имеет разную область выполнения с вызывающим, eval - одинаковыми. Но это правило действует только до ES6, в ES6 и в будущем eval будет иметь то же поведение с функцией.