Eval () ve new Function () aynı şey midir?


92

Bu iki işlev perde arkasında aynı şeyi mi yapıyor? (tek ifadeli işlevlerde)

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
Aslında bu jQuery 1.7.2 satır
573'te

2
newBu tartışmada neden düşünülüyor? Functionörtük olarak somutlaştırır a function object. Hariç tutmak new, kodu hiç değiştirmeyecektir. İşte bunu gösteren bir jsfiddle: jsfiddle.net/PcfG8
Travis J

Yanıtlar:


117

Hayır, aynı değiller .

  • eval() bir dizeyi geçerli yürütme kapsamında bir JavaScript ifadesi olarak değerlendirir ve yerel değişkenlere erişebilir.
  • new Function()Bir dizede depolanan JavaScript kodunu, daha sonra çağrılabilen bir işlev nesnesine ayrıştırır. Kod ayrı bir kapsamda çalıştığı için yerel değişkenlere erişemez.

Bu kodu düşünün:

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

Eğer new Function('return (a = 22);')()kullanıldı, yerel değişken adeğerini koruyacak. Bununla birlikte, Douglas Crockford gibi bazı JavaScript programcıları , kesinlikle gerekli olmadıkça hiçbirinin kullanılmaması gerektiğine inanmaktadır ve yapıcıyı güvenilmeyen veriler üzerinde değerlendirmenin / kullanmanın güvenli ve akıllıca olmadığını düşünmektedir .Function


11
"asla kullanılmamalıdır" bu kadar geniş bir ifadedir. Peki ya, herhangi bir girdi kontrolünüz dışında olduğunda asla kullanılmamalıdır. Bunu söyledikten sonra, JSON'u ayrıştırmak dışında asla kullanmaya ihtiyacım olmadı. Ancak burada geçerli kullanımlar gibi görünen soruları yanıtladım, yöneticilerin bir son kullanıcıların kullanabileceği şablon oluşturma işlevleri oluşturmasına izin vermek gibi bir şey içeriyordu. Bu durumda, girdi bir yönetici tarafından oluşturulmuştur, bu nedenle kabul edilebilirdi
Juan Mendes

3
@Juan: Crockford'un amacı, eval'un genellikle kötüye kullanılmasıdır (sizin bakış açınıza bağlıdır), bu nedenle "en iyi uygulamalar" JavaScript'inden çıkarılmalıdır. Bununla birlikte, JSON gibi kullanımlar için veya girdi ilk doğru şekilde doğrulandığında aritmetik ifade ayrıştırması için yararlı olduğunu kabul ediyorum. Crockford bile bunu JSON kitaplığı json2.js'de kullanıyor.
Lütfen

Öyleyse bu , bunun tamamen yeni bir uygulama bağlamıyla new Function(code)aynı olduğu anlamına eval('(function(){'+code+'})()')mı geliyor?
George Mauer

5
@GeorgeMauer: Sanırım eval('(function(){'+code+'})')bir işlev nesnesi döndürecek olanı demek istediniz . MDN'ye göre , "Function yapıcısı ile oluşturulan işlevler, kendi oluşturma bağlamlarına kapatma oluşturmaz; her zaman pencere bağlamında çalışırlar (işlev gövdesi" sıkı kullan "ifadesiyle başlamadıkça; bu durumda bağlam tanımsızdır) . "
Lütfen

6

Hayır.

Güncellemenize olarak, yapılan çağrılar evaluateve funcaynı sonucu üretir. Ancak, kesinlikle "perde arkasında aynı şeyi yapmıyorlar". funcFonksiyon yeni bir işlev oluşturur, ancak buna karşın hemen ardından, onu çalıştırır evaluateişlevi basitçe yerinde kodunu çalıştırır.

Orijinal sorudan:

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

Bunlar size çok farklı sonuçlar verecektir:

evaluate('0) + (4');
func('0) + (4');

Her durumda, en istisnai durumlar dışında her ikisi de kötü bir uygulamadır.
palswim

8
Örneğinizi uygulamasına göre uydurdunuz. Değerlendirmeyi uygulamış return eval('(' + string + ')');olsaydı, aynı sonuçları verirlerdi.
Juan Mendes

@Juan Düşünmedim ama evet. Soruyu
düzenledi

6

new Functionyeniden kullanılabilen bir işlev oluşturur. evalsadece verilen dizgeyi çalıştırır ve son ifadenin sonucunu döndürür. Bir eval taklit etmek için Function kullanan bir sarmalayıcı işlevi oluşturmaya çalıştığınızda sorunuz yanlış yönlendirilmiş.

Perdelerin arkasında bazı kodlar paylaştıkları doğru mu? Evet, büyük ihtimalle. Tam olarak aynı kod mu? Hayır, kesinlikle.

Eğlence için, burada bir işlev oluşturmak için eval kullanarak kendi kusurlu uygulamam. Umarım farkı biraz aydınlatır!

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

Bu ve yeni İşlev arasındaki en büyük fark, İşlevin sözcüksel olarak kapsamlı olmamasıdır. Böylece kapanış değişkenlerine erişimi olmazdı ve benimki olur.


arguments.slice()for döngüsü yerine neden kullanılmasın ? Veya argümanlar gerçek bir dizi değilse [].slice.call(arguments, 1),.
Xeoncross

3

Buradaki örneklerde kullanılan bazı sözdizimlerini ve bunun ne anlama geldiğini belirtmek isterim:

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

Fonksiyonun (...) () sonunda "()" olduğuna dikkat edin. Bu sözdizimi, func'ın yeni işlevi çalıştırmasına ve dizeyi, dize döndüren bir işlev değil, ancak aşağıdakileri kullanırsanız döndürmesine neden olur:

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

Şimdi func, bir dizge döndüren bir işlev döndürecektir.


2

Yani, aynı sonuçları verecek mi, o zaman evet ... ama sadece değerlendirmek (diğer bir deyişle, "bu JavaScript dizisini değerlendirmek") çok daha kolay olacaktır.

Aşağıda DÜZENLE:

Demek gibi ... bu iki matematik problemi aynı mı:

1 + 1

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


ikisi de dizeyi yeniden ayrıştırıyor mu?
qwertymk

ikisi de dizeyi ayrıştırır (kod örneğinizde). "yeniden ayrıştırmak" ile ne demek istediğini bilmiyorum.
Timothy Khouri

1
Eminim her ikisi de dizeyi bir noktada ayrıştırırlar (değerlendirirler), ancak Functionnesne muhtemelen dizeyi evalişlevi çağırdığınızda özel bir üye değişkeni içinde saklar .
palswim

1

Bu örnekte sonuçlar aynı, evet. Her ikisi de geçtiğiniz ifadeyi yürütür. Onları bu kadar tehlikeli yapan da budur.

Ama sahnenin arkasında farklı şeyler yapıyorlar. new Function()Sahne arkasını içeren , sağladığınız koddan anonim bir işlev oluşturur ve bu işlev çağrıldığında çalıştırılır.

Ona ilettiğiniz JavaScript, anonim işlevi çağırana kadar teknik olarak çalıştırılmaz. Bu, eval()kodu hemen yürütenin aksine ve ona dayalı bir işlev oluşturmaz.


Biraz daha açıklayabilir misin? İade ifadesinde ikisi de idam edilmedi mi? Function () biri eval'dan başka bir yığın çağrı düzeyi kullanıyor mu?
qwertymk

Does the Function() one use another stack call level than eval?: Öyle olduğunu varsayıyorum çünkü eval()girdinizden bir fonksiyon yaratmıyor - sadece onu çalıştırıyor. new Function()daha sonra çağırdığı yeni bir işlev oluşturur.
Chris Laplante

@SimpleCoder: Function () çağrı yığınına hiçbir şey eklemez. Yalnızca sonuçta ortaya çıkan işlevi çağırırsanız. eval aynı şeyi yapar (soru bağlamında uygulanırsa)
Juan Mendes
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.