JavaScript'te (1, eval) ('bu') ile eval ('this') karşılaştırması?


85

JavaScript Kalıplarını okumaya başladım , bazı kodlar kafamı karıştırdı.

var global = (function () {
    return this || (1, eval)('this');
}());

İşte sorularım:

S1:

(1, eval) === eval?

Neden ve nasıl çalışıyor?

S2: Neden sadece

var global = (function () {
    return this || eval('this');
}());

veya

 var global = (function () {
    return this;
}());

Başlığı güncelledim çünkü bu özel bir durum. Ayrıca, belirli türden parantezler için parantezler : [] ve {} tamamen farklıdır :)

Yanıtlar:


104

(1,eval)Eski evalile düz eski arasındaki fark , birincinin bir değer ve ikincisinin bir değer olmasıdır. Başka bir tanımlayıcı olsaydı daha açık olurdu:

var x;
x = 1;
(1, x) = 1; //  syntax error, of course!

Bu, (1,eval)sonuç veren bir ifadedir eval(aynen (true && eval)ya da (0 ? 0 : eval)söyleyeceği gibi), ancak bu bir referans değildir eval.

Neden umurunda?

Eh, Ecma Spec bir düşünmektedir başvuru için eval"doğrudan eval çağrısı" olarak, ama sadece sağladığı konusunda bir ifade evalve dolaylı eval aramaları küresel kapsamda yürütülecek garanti edilir - dolaylı biri olmak.

Hala bilmediğim şeyler:

  1. Ne durum altında doğrudan eval çağrı gelmez değil küresel kapsamda yürütmek?
  2. Ne durum altında olabilir thisküresel kapsamında bir fonksiyonun değil küresel nesne verim?

Biraz daha bilgi toplanan olabilir burada .

DÜZENLE

Görünüşe göre, ilk sorumun cevabı "neredeyse her zaman". Doğrudan bir evalmesafede yürütür akım sahası. Aşağıdaki kodu göz önünde bulundurun:

var x = 'outer';
(function() {
  var x = 'inner';
  eval('console.log("direct call: " + x)'); 
  (1,eval)('console.log("indirect call: " + x)'); 
})();

Şaşırtıcı olmayan bir şekilde (heh-heh), bu çıktı:

direct call: inner
indirect call: outer

DÜZENLE

Daha fazla denemeden sonra, geçici olarak bunun veya thisolarak ayarlanamayacağını söyleyeceğim . Diğer yanlış değerlere (0, '', NaN, false) ayarlanabilir, ancak yalnızca çok kasıtlı olarak.nullundefined

Kaynağınızın hafif ve tersine çevrilebilir bir kranio-rektal inversiyondan muzdarip olduğunu ve Haskell'de bir hafta programlama yapmayı düşünebileceğini söyleyeceğim.


3
Vay canına, tüm valuevs lvalueşeyini bilmiyordum (pratikte belki, ama kelimelerle değil). Ne de ES5 kuralları değerlendiriyor (makul olarak evalhiç kullanmam gerekmediğinden ). Teşekkürler!
Stoive

Evet, evalpek çok çirkin keskin kenarı var ve yalnızca son çare olarak ve sonra çok, çok dikkatli kullanılmalıdır.
Malvolio

Yalnızca bir kez geçerli bir kullanımla karşılaştım - DOM'a eklenen bir komut dosyası etiketinin değerlendirilmesiinnerHtml
Stoive

1
lvalue, genellikle bir atamanın sol tarafında görünebilen ifadeye atıfta bulunduğundan, bu nedenle rvalue yerine lvalue adı olduğundan, doğrudan değerlendirmeyi belirlemekten çok az şey vardır. Bir değerlendirme çağrısı, yalnızca, tanımlayıcının evalbir CallExpression'un MemberExpression parçası olması gerektiğini ve standart evalişleve atıfta bulunduğunu belirten spesifikasyonun 15.1.2.1.1'de listelenen koşullar altında doğrudan yapılır .
chuckj

1
@Malvolio Lvalues'in, sahip olmadıkları doğrudan ve dolaylı değerlendirme ile bir ilgisi olduğunu ima ediyor gibisiniz. evalBir çağrı ifadesinin hedefi olarak adlandırılan bir tanımlayıcının kullanımı özeldir. ECMA'nın özel değil , özel referansı ele aldığını belirtiyorsunuz eval. Özel olan ve ifadenin standart evalişlev olarak değerlendirdiği çağrı ifadesindeki yerleşimdir . Örneğin var eval = window.eval; eval('1');, hala doğrudan window.eval('1')bir değerlendirmedir ve bu durumda da eval bir değer olsa bile değildir.
chuckj

33

Parça,

var global = (function () {  
    return this || (1, eval)('this');  
}());  

katı modda bile genel nesneyi doğru şekilde değerlendirir. Katı olmayan modda değeri thisgenel nesnedir, ancak katı modda budur undefined. İfade (1, eval)('this')her zaman genel nesne olacaktır. Bunun nedeni, dolaylı âyetlerin etrafındaki kuralları içermektedir eval. Doğrudan çağrılar eval, arayanın kapsamına sahiptir ve dize , kapanıştaki thisdeğeri olarak değerlendirilir this. Dolaylı evals, genel kapsamda, küresel kapsamdaki bir işlev içinde çalıştırılmış gibi değerlendirilir. Bu işlevin kendisi bir katı mod işlevi olmadığından, genel nesne olarak aktarılır thisve ardından ifade 'this', küresel nesne olarak değerlendirilir. İfade (1, eval), zorlamanın süslü bir yoludur.eval dolaylı olmak ve genel nesneyi döndürmek.

A1: Dolaylı ayetin doğrudan çağrıları etrafındaki özel kurallar nedeniyle (1, eval)('this')aynı değildir .eval('this')eval

A2: Orijinal katı modda çalışır, değiştirilmiş sürümler çalışmaz.


12

Q1'e kadar:

Bunun JS'de virgül operatörü için iyi bir örnek olduğunu düşünüyorum. Bu makaledeki virgül operatörü açıklamasını beğendim: http://javascriptweblog.wordpress.com/2011/04/04/the-javascript-comma-operator/

Virgül operatörü her iki işlenenini de (soldan sağa) değerlendirir ve ikinci işlenenin değerini döndürür.

2. çeyreğe kadar:

(1, eval)('this')ES5'te global olarak kod yürüten dolaylı değerlendirme çağrısı olarak kabul edilir. Dolayısıyla sonuç, genel bağlam olacaktır.

Bkz. Http://perfectionkills.com/global-eval-what-are-the-options/#evaling_in_global_scope


7

S1: Virgülle ayrılmış birden çok ardışık javascript ifadesi, son ifadenin değerini alır. Yani:

(1, eval)işleve bir işlev referansı olan sonuncunun değerini alır eval(). Görünüşe göre, eval()çağrıyı ES5'te küresel kapsamda değerlendirilecek dolaylı bir değerlendirme çağrısına dönüştürmek için bu şekilde yapıyor. Ayrıntılar burada açıklanmıştır .

S2: Global tanımlamayan this, ancak tanımlayan bir ortam olmalı eval('this'). Bunun için düşünebilmemin tek nedeni bu.


Belki birileri, izin vermeyen bir check-in kancasından kaçmaya çalışıyor /eval\(/g?
Stoive

@Stoive - evet ben de böyle bir şeyi merak ettim. Bir iade kancası değilse, bazıları işlemin bir yerini filtreler (belki küçültme).
jfriend00

7
ES5 katı moduyla bir ilgisi var. ES5 katı modunda AFAIK herhangi bir eval'd kodu, genel bağlam veya çevreleyen bağlam yerine kendi bağlamında yürütülür. Bunu aşmanın bir yolu, söz konusu kodun yaptığı gibi ona dolaylı olarak atıfta bulunmaktır.
Cristian Sanchez


Cevabım, CDSanchez ve @Saxoier'den gelen bilgileri içerecek şekilde güncellendi. Teşekkür.
jfriend00
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.