Apakah eval () dan new Function () sama?

92

Apakah kedua fungsi ini melakukan hal yang sama di balik layar? (dalam fungsi pernyataan tunggal)

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.dll
sumber
3
Sebenarnya ini digunakan di jQuery 1.7.2 baris 573. Meskipun dengan "beberapa pemeriksaan keamanan"
PicoCreator
2
Mengapa newdipertimbangkan dalam diskusi ini? Functionsecara implisit memberi contoh a function object. Mengecualikan newtidak akan mengubah kode sama sekali. Berikut ini adalah jsfiddle yang menunjukkan bahwa: jsfiddle.net/PcfG8
Travis J

Jawaban:

117

Tidak, mereka tidak sama.

  • eval() mengevaluasi string sebagai ekspresi JavaScript dalam cakupan eksekusi saat ini dan dapat mengakses variabel lokal.
  • new Function()mengurai kode JavaScript yang disimpan dalam string menjadi objek fungsi, yang kemudian dapat dipanggil. Itu tidak dapat mengakses variabel lokal karena kode berjalan dalam lingkup terpisah.

Pertimbangkan kode ini:

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

Jika new Function('return (a = 22);')()digunakan, variabel lokal aakan mempertahankan nilainya. Namun demikian, beberapa programmer JavaScript seperti Douglas Crockford percaya bahwa keduanya tidak boleh digunakan kecuali benar-benar diperlukan , dan menghindari / menggunakan Functionkonstruktor pada data yang tidak tepercaya adalah tidak aman dan tidak bijaksana.

Harap Berdiri
sumber
11
"tidak boleh digunakan" adalah pernyataan yang begitu luas. Bagaimana kalau, jangan pernah digunakan ketika salah satu input di luar kendali Anda. Karena itu, saya tidak pernah perlu menggunakannya, kecuali untuk mengurai JSON. Tapi saya telah menjawab pertanyaan di sini yang sepertinya penggunaan yang valid, itu melibatkan sesuatu seperti mengizinkan admin untuk menghasilkan fungsi template yang dapat digunakan oleh pengguna akhir. Dalam hal ini masukan dihasilkan oleh admin, jadi dapat diterima
Juan Mendes
3
@Juan: Maksud Crockford adalah bahwa eval sering disalahgunakan (bergantung pada perspektif Anda), jadi harus dikecualikan dari JavaScript "praktik terbaik". Saya setuju, bagaimanapun, bahwa itu berguna untuk penggunaan seperti JSON atau penguraian ekspresi aritmatika ketika input pertama kali divalidasi dengan benar. Bahkan Crockford menggunakannya di pustaka JSON json2.js miliknya.
Harap Berdiri
Jadi apakah ini berarti new Function(code)sama dengan eval('(function(){'+code+'})()')atau apakah ini konteks eksekusi yang sama sekali baru?
George Mauer
5
@ GeorgeMauer: Saya pikir maksud Anda eval('(function(){'+code+'})'), yang akan mengembalikan objek fungsi. Menurut MDN , "Fungsi yang dibuat dengan konstruktor Fungsi tidak membuat penutupan untuk konteks pembuatannya; mereka selalu berjalan dalam konteks jendela (kecuali badan fungsi dimulai dengan pernyataan" gunakan ketat "; dalam hal ini konteksnya tidak ditentukan) . "
Harap Berdiri
6

Tidak.

Dalam pembaruan Anda, panggilan ke evaluatedan funcmenghasilkan hasil yang sama. Tapi, mereka pasti tidak "melakukan hal yang sama di belakang layar". The funcFungsi menciptakan fungsi baru, tapi kemudian segera mengeksekusinya, sedangkan evaluatefungsi hanya mengeksekusi kode di tempat.

Dari pertanyaan awal:

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

Ini akan memberi Anda hasil yang sangat berbeda:

evaluate('0) + (4');
func('0) + (4');
palswim
sumber
Bagaimanapun, keduanya adalah praktik buruk dalam semua kasus kecuali kasus yang paling luar biasa.
palswim
8
Nah, Anda memalsukan contoh Anda sesuai dengan implementasinya. Jika dia menerapkan evaluasi return eval('(' + string + ')');maka mereka akan menghasilkan hasil yang sama.
Juan Mendes
@Juan aku tidak berpikir untuk tapi ya. Diedit pertanyaan
qwertymk
6

new Functionmenciptakan fungsi yang dapat digunakan kembali. evalhanya mengeksekusi string yang diberikan dan mengembalikan hasil dari pernyataan terakhir. Pertanyaan Anda keliru saat Anda mencoba membuat fungsi pembungkus yang menggunakan Fungsi untuk meniru eval.

Benarkah mereka berbagi beberapa kode di balik tirai? Ya, sangat mungkin. Kode yang persis sama? Tidak, tentu.

Untuk bersenang-senang, inilah implementasi saya yang tidak sempurna menggunakan eval untuk membuat fungsi. Semoga ini menjelaskan perbedaannya!

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

Perbedaan terbesar antara ini dan Fungsi baru adalah bahwa Fungsi tidak dicakup secara leksikal. Jadi itu tidak akan memiliki akses ke variabel penutupan dan saya akan.

Juan Mendes
sumber
mengapa tidak menggunakan arguments.slice()for loop? Atau jika argumen bukan array yang benar [].slice.call(arguments, 1),.
Xeoncross
3

Hanya ingin menunjukkan beberapa sintaks yang digunakan dalam contoh di sini dan apa artinya:

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

perhatikan bahwa Fungsi (...) () memiliki "()" di akhir. Sintaks ini akan menyebabkan func menjalankan fungsi baru dan mengembalikan string bukan fungsi yang mengembalikan string, tetapi jika Anda menggunakan berikut ini:

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

Sekarang func akan mengembalikan fungsi yang mengembalikan string.

Jack D Menendez
sumber
2

Jika yang Anda maksud, apakah itu akan menghasilkan hasil yang sama, maka ya ... tetapi hanya untuk eval (alias, "evaluasi string JavaScript ini") akan jauh lebih sederhana.

EDIT Di Bawah:

Ini seperti mengatakan ... apakah kedua soal matematika ini sama:

1 + 1

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

Timothy Khouri
sumber
apakah mereka berdua mengurai ulang string?
qwertymk
mereka berdua akan mengurai string (dalam contoh kode Anda). tidak tahu apa yang Anda maksud dengan "parse ulang".
Timothy Khouri
1
Saya yakin mereka berdua mengurai (mengevaluasi) string di beberapa titik, tetapi Functionobjek mungkin menyimpan string dalam variabel anggota privat evalketika Anda memanggil fungsi.
palswim
1

Dalam contoh itu, hasilnya sama, ya. Keduanya menjalankan ekspresi yang Anda berikan. Inilah yang membuat mereka sangat berbahaya.

Tapi mereka melakukan hal yang berbeda di balik scense. Yang melibatkan new Function(), di belakang layar, membuat fungsi anonim dari kode yang Anda berikan, yang dijalankan saat fungsi tersebut dipanggil.

JavaScript yang Anda berikan secara teknis tidak dijalankan sampai Anda menjalankan fungsi anonim. Ini berbeda dengan eval()yang langsung mengeksekusi kode, dan tidak menghasilkan fungsi berdasarkan kode tersebut.

Chris Laplante
sumber
Bisakah Anda menjelaskan lebih banyak? Bukankah mereka berdua dieksekusi dalam pernyataan pengembalian? Apakah Function () satu menggunakan tingkat panggilan tumpukan lain daripada eval?
qwertymk
Does the Function() one use another stack call level than eval?: Saya akan berasumsi demikian, karena eval()tidak membuat fungsi dari input Anda - itu hanya mengeksekusinya. new Function()membuat fungsi baru, yang kemudian dipanggil.
Chris Laplante
@SimpleCoder: Function () tidak menambahkan apa pun ke tumpukan panggilan. Hanya jika Anda memanggil fungsi yang dihasilkan. eval melakukan hal yang persis sama (jika diterapkan dalam konteks pertanyaan)
Juan Mendes