Чи 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'));

3
Насправді це використовується в рядку 573. jQuery 1.7.2. Хоча з "деякими перевірками безпеки"
PicoCreator

2
Чому newрозглядається в цій дискусії? Functionнеявно створює екземпляр a function object. Виключення newне змінить код взагалі. Ось jsfiddle, що демонструє це: jsfiddle.net/PcfG8
Тревіс Дж.

Відповіді:


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, такі як Дуглас Крокфорд, вважають, що жоден з них не слід використовувати, якщо це не є абсолютно необхідним , а оцінка / використання Functionконструктора на ненадійних даних є небезпечним і нерозумним.


11
"ніколи не слід використовувати" - таке широке твердження. Як щодо того, ніколи не слід використовувати, коли будь-який з входів знаходиться поза вашим контролем. Сказавши це, мені ніколи не потрібно було ним користуватися, за винятком аналізу JSON. Але я відповів тут на запитання, які здавались допустимими, це стосувалося чогось типу дозволу адміністраторам генерувати функції шаблонування, які могли б використовувати кінцеві користувачі. У цьому випадку вхідні дані були згенеровані адміністратором, тому це було прийнятно
Хуан Мендес,

3
@Juan: Суть Крокфорда полягає в тому, що eval часто зловживають (це залежить від вашої точки зору), тому його слід виключити з "найкращих практик" JavaScript. Проте я погоджуюсь, що це корисно для таких видів використання, як JSON або синтаксичний аналіз арифметичних виразів, коли введення спочатку перевіряється належним чином. Навіть Крокфорд використовує його у своїй бібліотеці JSON json2.js.
Будь ласка, зупиніться

То чи це означає, що new Function(code)це те саме, що це eval('(function(){'+code+'})()')чи це абсолютно новий контекст виконання?
Джордж Мауер

5
@GeorgeMauer: Думаю, ви маєте на увазі eval('(function(){'+code+'})'), що поверне об'єкт функції. Згідно з MDN , "Функції, створені за допомогою конструктора функцій, не створюють закриття для контекстів їх створення; вони завжди працюють у контексті вікна (якщо тіло функції не починається з" використовувати строго "; оператор, у цьому випадку контекст не визначений) . "
Будь ласка, зупиніться

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

8
Ну, ви обманули свій приклад відповідно до його реалізації. Якби він застосував оцінку, як return eval('(' + string + ')');тоді, вони дали б однакові результати.
Хуан Мендес,

@Juan Я не думав, але так. Редагував питання
qwertymk

6

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]');
}

Найбільша різниця між цією та новою функцією полягає в тому, що функція не має лексичного масштабу. Тож він не мав би доступу до змінних закриття, а мій - мав би.


чому б не використовувати arguments.slice()замість циклу for? Або , якщо аргументи не є істинним масив [].slice.call(arguments, 1).
Xeoncross

3

Просто хочу вказати на деякий синтаксис, що використовується в прикладах тут, і на те, що це означає:

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

зверніть увагу, що функція (...) () має в кінці "()". Цей синтаксис змусить функцію виконувати нову функцію і повертати рядок не функцією, яка повертає рядок, але якщо ви використовуєте наступне:

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

Тепер func поверне функцію, яка повертає рядок.


2

Якщо ви маєте на увазі, чи дасть це однакові результати, тоді так ... але просто оцінити (тобто "оцінити цей рядок JavaScript") було б набагато простіше.

РЕДАКТУВАТИ нижче:

Це все одно, що сказати ... ці дві математичні задачі однакові:

1 + 1

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


вони обидва повторно аналізують рядок?
qwertymk

вони обидва проаналізують рядок (у прикладі коду). не знаю, що ви маєте на увазі під "повторним розбором".
Timothy Khouri

1
Я впевнений, що вони обоє аналізують (оцінюють) рядок у якийсь момент, але Functionоб’єкт, ймовірно, зберігає рядок у приватній змінній члена, evalколи ви викликаєте функцію.
palswim

1

У цьому прикладі результати однакові, так. Обидва виконують переданий вами вираз. Саме це робить їх такими небезпечними.

Але вони роблять різні речі за ароматом. Той, хто бере участь new Function()за кадром, створює анонімну функцію з коду, який ви надаєте, і яка виконується під час виклику функції.

Переданий йому JavaScript технічно не виконується, доки ви не викликаєте анонімну функцію. Це на відміну від того, eval()який виконує код відразу і не генерує на основі нього функції.


Чи можете ви викласти ще трохи? Чи не виконуються вони обоє в операторі повернення? Чи використовує Function () інший рівень виклику стека, ніж eval?
qwertymk

Does the Function() one use another stack call level than eval?: Я вважаю, що так, оскільки eval()не створює функцію з вашого вводу - вона просто виконує її. new Function()створює нову функцію, яку потім викликає.
Chris Laplante

@SimpleCoder: Функція () не додає нічого до стеку викликів. Тільки якщо ви викликаєте отриману функцію. eval робить точно те саме (якщо застосовується в контексті питання)
Хуан Мендес
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.