Eval () и new Function () - одно и то же?

92

Эти две функции делают то же самое за кулисами? (в функциях с одним оператором)

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'));
qwertymk
источник
3
Фактически это используется в jQuery 1.7.2, строка 573. Хотя с «некоторыми проверками безопасности»
PicoCreator
2
Почему newрассматривается в этом обсуждении? Functionнеявно создает экземпляр function object. Исключение newвообще не изменит код. Вот jsfiddle, демонстрирующий это: jsfiddle.net/PcfG8
Travis J

Ответы:

117

Нет, они не такие.

  • eval() оценивает строку как выражение JavaScript в текущей области выполнения и может обращаться к локальным переменным.
  • new Function()анализирует код JavaScript, хранящийся в строке, в объект функции, который затем может быть вызван. Он не может получить доступ к локальным переменным, потому что код выполняется в отдельной области.

Рассмотрим этот код:

function test1() {
    var a = 11;
    eval('(a = 22)');
    alert(a);            // alerts 22
}

Если бы new Function('return (a = 22);')()они использовались, локальная переменная aсохранила бы свое значение. Тем не менее, некоторые программисты JavaScript , такие как Дуглас Crockford считают , что ни один не должно использоваться , если это абсолютно необходимо , и evaling / с помощью Functionконструкторы на ненадежных данных является небезопасным и неразумно.

Пожалуйста
источник
11
«никогда не следует использовать» - такое широкое заявление. Как насчет того, никогда не следует использовать, когда какой-либо ввод находится вне вашего контроля. Сказав это, мне никогда не нужно было его использовать, кроме разбора JSON. Но я ответил на вопросы здесь, которые казались допустимыми, это включало что-то вроде разрешения администраторам создавать функции шаблонов, которые могли бы использовать конечные пользователи. В этом случае ввод был создан администратором, поэтому он был приемлемым
Хуан Мендес
3
@Juan: Крокфорд считает, что eval часто используется неправильно (в зависимости от вашей точки зрения), поэтому его следует исключить из "лучших практик" JavaScript. Однако я согласен с тем, что это полезно для таких целей, как JSON или анализ арифметических выражений, когда ввод сначала правильно проверяется. Даже Крокфорд использует его в своей библиотеке JSON json2.js.
PleaseStand 05
Означает ли это, что new Function(code)это то же самое, eval('(function(){'+code+'})()')или это совершенно новый контекст выполнения?
Джордж Мауэр
5
@GeorgeMauer: Я думаю, вы имеете в виду eval('(function(){'+code+'})'), что возвращает объект функции. Согласно MDN , «функции, созданные с помощью конструктора функций, не создают замыканий для своих контекстов создания; они всегда выполняются в контексте окна (если только тело функции не начинается с оператора« use strict », и в этом случае контекст не определен). . "
PleaseStand 07
6

Нет.

В вашем обновлении вызовы 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');
приятель
источник
В любом случае и то и другое - плохая практика во всех случаях, кроме самых исключительных.
palswim 05
8
Ну, вы обманули свой пример в соответствии с его реализацией. Если бы он реализовал оценку как, return eval('(' + string + ')');тогда они дали бы те же результаты.
Хуан Мендес
@ Хуан, я не думал, но да. Отредактировал вопрос
qwertymk 05
6

new Functionсоздает функцию, которую можно использовать повторно. evalпросто выполняет заданную строку и возвращает результат последнего оператора. Ваш вопрос ошибочен, поскольку вы пытались создать функцию-оболочку, которая использует Function для имитации 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]');
}

Самая большая разница между этой функцией и новой функцией заключается в том, что функция не имеет лексической области видимости. Так что у него не было бы доступа к закрывающим переменным, как у меня.

Хуан Мендес
источник
почему бы не использовать arguments.slice()вместо цикла for? Или , если аргументы не является истинным массив [].slice.call(arguments, 1).
Xeoncross
3

Просто хочу указать на синтаксис, используемый в приведенных здесь примерах, и на то, что он означает:

 var func = function(string) {
     return (new Function( 'return (' + string + ')' )());
 }

обратите внимание, что функция (...) () имеет в конце "()". Этот синтаксис заставит func выполнить новую функцию и вернуть строку, а не функцию, которая возвращает строку, но если вы используете следующее:

 var func = function(string) {
     return (new Function( 'return (' + string + ')' ));
 }

Теперь func вернет функцию, возвращающую строку.

Джек Д. Менендес
источник
2

Если вы имеете в виду, даст ли он те же результаты, тогда да ... но просто eval (также известный как «оценить эту строку JavaScript») было бы намного проще.

ИЗМЕНИТЬ ниже:

Это как сказать ... эти две математические задачи одинаковы:

1 + 1

1 + 1 + 1 - 1 + 1 - 1 * 1/1

Тимоти Хури
источник
они оба повторно разбирают строку?
qwertymk 05
они оба будут анализировать строку (в вашем примере кода). не знаю, что вы имеете в виду под «повторным синтаксическим анализом».
Timothy Khouri
1
Я уверен, что они оба анализируют (оценивают) строку в какой-то момент, но Functionобъект, вероятно, хранит строку в частной переменной-члене, evalкогда вы вызываете функцию.
palswim 05
1

В этом примере результаты такие же, да. Оба выполняют переданное вами выражение. Вот что делает их такими опасными.

Но за сценой они делают разные вещи. Тот, который вовлекает new Function()за кулисами, создает анонимную функцию из предоставленного вами кода, который выполняется при вызове функции.

Переданный вами код JavaScript технически не выполняется, пока вы не вызовете анонимную функцию. Это отличается от того, eval()что выполняет код сразу, а не генерирует на его основе функцию.

Крис Лапланте
источник
Вы можете еще немного разъяснить? Разве они оба не выполняются в операторе возврата? Использует ли функция () другой уровень вызова стека, чем eval?
qwertymk 05
Does the Function() one use another stack call level than eval?: Я бы так предположил, потому eval()что не создает функцию из вашего ввода - он просто выполняет ее. new Function()создает новую функцию, которую затем вызывает.
Крис Лапланте
@SimpleCoder: Function () ничего не добавляет в стек вызовов. Только если вы вызовете получившуюся функцию. eval делает то же самое (если применяется в контексте вопроса)
Хуан Мендес