Neden! {} [True], JavaScript'te doğru olarak değerlendirilir?


131

{}[true]olduğu [true]ve ![true]olması gerektiği false.

Öyleyse neden !{}[true]değerlendiriyor true?


30
var o = {}; o[true] === undefined.
azz

2
Buradaki açıklama muhtemelen bu önceki soruda
IMSoP

45
"Çünkü Javascript aptalca" muhtemelen aradığınız cevap değil.
georg

2
Bahsedildiği gibi, {}[true] === [true]bir konsoldan alıyorsanız , bunun nedeni {}bir nesne değil, boş bir kod bloğu muamelesi yapmasıdır.
azz

3
o yardımcı olabilir, karşılaştırmak için denemek {}ve ({})Konsolun (veya içinde {}[true]ve ({})[true]). Ayrıca, kimsenin bahsetmediği gibi, nesne [true], ["true"] nesnesi olarak değerlendirilir.
BiAiB

Yanıtlar:


172

Bunun nedeni {}[true], Plain'in boş bir ifade bloğu (bir nesne değişmezi değil) ve ardından içeren bir dizi olarak ayrıştırılması true, ki bu true.

Öte yandan, tatbik !operatör ayrıştırıcı yorumlama yapar {}şu nedenle, bir amacı sabit değer olarak {}[true]döndürdüğü bir üyesi erişim olur undefined, ve !{}[true]gerçekten de true(şekilde !undefinedolduğu true).


25
Tanımlanmamış gerçeği ise hala affedilemez.
evilcandybag

87
@evilcandybag: Kesinlikle değil. undefinedyanlıştır (sık sık güvendiğimiz bir şey - if (obj.maybeExists) ...), bu yüzden doğru olan mükemmel mantıksal anlam ifade eder !undefined.
josh3736

8
@Josh, bence evilcandybag null, !undefinedeşit olmakla birlikte bazı dillerde benzer bir davranışı tercih ederdi undefined. Javascript'te durum böyle değil.
Frédéric Hamidi

6
@evilcandybag: not undefined( !undefined) olan bir şeyin bu nedenle tanımlanması gerektiğini söylemek yalnızca mantıklıdır . Bir şey tanımlanmışsa, genellikle olarak yorumlanır true.
OozeMeister

7
@Cruncher Eğer a tanımlanmamışsa ve b tanımlanmamışsa, a! = B olduğunu nasıl bilebiliriz? Özellikle iki değişkenin bilinen tek özelliği tamamen aynı olduğunda.
LJ2

44

Çünkü {}[true]dönmez true, ancak undefinedve undefinedolarak değerlendirilir false:

http://jsfiddle.net/67GEu/

'use strict';
var b = {}[true];
alert(b); // undefined
b = !{}[true];
alert(b); // true

21
{}[true]Bir konsolda değerlendirirseniz , elde edersiniz [true], çünkü {}bir nesne değil, boş bir kod bloğu olarak yorumlanır. Her şey bağlamı ve belirsizliğiyle ilgili {}.
IMSoP

1
@IMSoP ama neden {key:"value"}[1,2,3];de değerlendiriliyor [1,2,3]?
t.niese

3
@ t.niese, çünkü bir etiket ( key:) ve bir dize değişmezi ( "value") ve ardından bir dizi içeren bir ifade bloğu olarak ayrıştırılır . Ayrıştırıcı hala bir nesne değişmezi görmüyor.
Frédéric Hamidi

1
@ FrédéricHamidi ah evet, işte bu. Etiketleri bastırdım ^^
t.niese

1
@dooxe Diğer cevapları okuyun; her şey yorumlandığı bağlamla ilgilidir. Eğer onu sararsanız alert()veya console.log()bir değişkene atarsanız, bağlamı değiştirmiş olursunuz, bu nedenle konsolda kendi başına yazılanla aynı şekilde davranmaz.
IMSoP

27

Çünkü

{}[true]

olarak değerlendirilir undefinedve !undefinedöyle true.

@Schlingel'den:

trueanahtar ve {}karma harita olarak kullanılır . Anahtarı olan bir özellik trueolmadığından geri döner undefined. Değil undefinededilir true, beklendiği gibi.

Konsol oturumu ( Node.js [0.10.17] ):

> {}[true]
undefined
> !{}[true]
true
> [true]
[ true ]
> ![true]
false
>

Ancak, Google Chrome konsolunda:

> !{}[true]
true

Yani tutarsızlık yok. Muhtemelen JavaScript VM'nin eski bir sürümünü kullanıyorsunuz. Daha fazla kanıta ihtiyaç duyanlar için:

Buraya resim açıklamasını girin

GÜNCELLEME

İle Firefox , o da sonucunu true:

Buraya resim açıklamasını girin


Yaparsanız eval('{}[true]')veya konsola yazarsanız değil . Sonra mesela als {}"test"olduğunu testbile ya {key:"value"}"test"olduğu test.
t.niese

İlginç, bunu hangi js motorunda test ediyorsunuz?
t.niese

@ t.niese Bunu düğüm konsoluma yazdım ve elimde bu var.
Games Brainiac

Sadece meraktan. {}[true];( İle ;) [true]sizin için geri mi dönüyor , çünkü burada mı?
t.niese

2
Erkeklere olumsuz oy vermenin nedeni? Buna 8 oyla neredeyse aynı cevap var ve olumsuz oy mu alıyorum? Neyi yanlış yaptım?
Games Brainiac

23

Kafa karışıklığının nedeni, ilk iddianızın yanlış anlaşılmasından kaynaklanıyor:

{}[true] dır-dir [true]

Çalıştırdığınızda gördüğünüz şey bir belirsizliğin sonucudur. Javascript, bunun gibi belirsizliklerin nasıl ele alınacağına dair tanımlanmış bir kurala sahiptir ve bu durumda, bir işaret ifadesi olarak gördüğünüzü iki ayrı ifadeye böler.

Yani Javascript yukarıdaki kodu iki ayrı ifade olarak görüyor: Birincisi bir var {}ve sonra tamamen ayrı bir tane var [true]. İkinci ifade, size sonucu veren şeydir [true]. İlk ifade {}etkili bir şekilde tamamen görmezden gelinmiştir.

Aşağıdakileri deneyerek bunu kanıtlayabilirsiniz:

({}[true])

yani, yorumlayıcıyı tek bir ifade olarak okumaya zorlamak için her şeyi parantez içine almak.

Şimdi ifadenizin gerçek değerinin olduğunu göreceksiniz undefined. (bu aynı zamanda sonraki bölümü anlamamıza da yardımcı olacaktır)

Artık sorunuzun ilk kısmının kırmızı ringa balığı olduğunu biliyoruz, bu yüzden sorunun son kısmına geçelim:

Öyleyse neden! {} [True] doğru olarak değerlendiriliyor?

Burada da aynı ifadeye sahibiz, ancak !önüne bir ek eklenmiştir.

Bu durumda, Javascript'in kuralları ona her şeyi tek bir ifade olarak değerlendirmesini söyler.

Önceki ifadeyi parantez içine aldığımızda ne olduğuna geri dönün; biz var undefined. Bu sefer aynı şeyi etkili bir şekilde yapıyoruz, ancak !önüne bir koyuyoruz . Yani kodunuz !undefined, olan gibi basitleştirilebilir true.

Umarım bu biraz açıklar.

Bu karmaşık bir canavar, ancak burada öğrenilecek ders, konsolda bunları değerlendirirken ifadelerinizin etrafına köşeli parantezler kullanmak ve bunun gibi sahte sonuçlardan kaçınmaktır.


2
Sanmıyorum {}[true]olduğunu geçersiz , tam olarak sadece belirsiz . Bu, "boş kod bloğu ve ardından değişmez dizi" veya "özelliği olmayan, bir özelliğe erişilen sabit nesne" olarak yorumlanabilir. İlkinin teknik olarak bir YSZ durumu olup olmadığını bilmiyorum (birçok dil zaten buraya noktalı virgül koymaz) ama sorunun özü, içeriğe duyarlı yorumdur.
IMSoP

@IMSoP - Siz yorumu göndermeden önce cevabı zaten düzenledim. :)
Spudley

1
Hâlâ cevabın başında "{} [doğru] aslında hiç geçerli değil" diyor.
IMSoP

Ayrıca, OP "demedi {}[true]olduğunu trueonlar" dedi " {}[true]olduğu [true]belirsiz beyanı iki geçerli yorumların biri olan,".
IMSoP

14

{}[true]olduğunu undefined. Bunu bulmak için şunu yazın:

a = {};
a[true] === undefined // true

ya da sadece:

({})[true] === undefined // true

Bunun !undefinedolduğunu biliyoruz true.


Gönderen @Benjamin Gruenbaum cevabı :

Chrome geliştirici araçları şunları yapar :

  try {
      if (injectCommandLineAPI && inspectedWindow.console) {
          inspectedWindow.console._commandLineAPI = new CommandLineAPI(this._commandLineAPIImpl, isEvalOnCallFrame ? object : null);
          expression = "with ((window && window.console && window.console._commandLineAPI) || {}) {\n" + expression + "\n}";
      }
      var result = evalFunction.call(object, expression);
      if (objectGroup === "console")
          this._lastResult = result;
      return result;
  } 
  finally {
      if (injectCommandLineAPI && inspectedWindow.console)
          delete inspectedWindow.console._commandLineAPI;
  }

Yani temel olarak, callifade ile nesne üzerinde bir gerçekleştirir . İfade şu şekildedir:

with ((window && window.console && window.console._commandLineAPI) || {}) {
    {}+{};// <-- This is your code
}

Gördüğünüz gibi, ifade sarma parantezleri olmadan doğrudan değerlendiriliyor.

Bu soruda daha fazla bilgi bulunabilir .


10

Buradaki cevaplar güzel, işte sözde kodda bir döküm:

  • {}['whatever'] = boş blok, NewArray ('ne olursa olsun') = NewArray ('ne olursa olsun')
  • {}[true] = boş blok, NewArray (true) = NewArray (true)
  • !{}['whatever'] = LogicalNOT (convertToBool (NewObject.whatever)) = LogicalNOT (convertToBool (tanımsız)) = MantıksalNOT (yanlış) = doğru
  • ({}['whatever']) = Gruplama (NewObject.whatever) = Gruplama (tanımsız) = tanımsız

8

Bunun nedeni {}, sizin anlamınıza göre değişmez sunumu değil Object, boş kapsam (veya boş kod bloğu) olmasıdır:

{ var a = 1 }[true] // [true] (do the same thing)

Yalnızca kapsam içindeki kodu değerlendirir ve ardından size dizinizi gösterir.

Ve senden

!{}[true]

Sadece bu kapsamı int'e dönüştürür ve aynı diziyi true olarak döndürür. Bu kodda bool kontrolü yoktur.

Ve sonucu kontrol etmeye çalışırsanız {}[true], aşağıdakileri alacaksınız false:

{}[true] -> [true] -> ![true] -> false

Daha fazla kapsam olmadığı için.

Yani !sorunuzda şununla aynı şeyi yapın:

!function() {
   //...
}

Bunu yaparsan daha kolay görülür var x = {}; x[true].
Chris Hayes

1
"Bu kapsama dönüştürülür" ile ne demek istediğinizden emin değilim; Ben lider ile düşünmek !o olduğu boş bir nesne değil, kapsam olarak yorumlanır ve bu tutarsızlık oluşur.
IMSoP

6
  • {} hiçbir özelliği olmayan bir nesnedir.
  • Yana []hemen bir nesneyi izler, "Bir dizi oluşturur" anlamına gelen "Erişim bu ismin bir özelliği" değil,
  • truebir boole'dir, ancak bir özellik adı olarak kullanılır, bu nedenle bir dizeye dönüştürülür ( "true")
  • Nesne adlı bir özelliği yoktur true(bu özelliği yok çünkü) bu yüzden {}['true']olduğuundefined
  • !undefinedatmalarını undefined(bir mantıksal değere false)
  • Değil operatör döner falseiçine true.

2
Durumunda {}[true](başka bir içeriği ile), {}bir değil, herhangi bir özelliklere sahip bir amacı, bu boş bir kod blok.
IMSoP


4

Biraz Daha Oynayalım!

İlk önce biraz eğlenelim !:

//----------#01#-----------
{}[true]; //[true]

//----------#02#-----------
var a = {}[true]; 
      console.log(a); //undefined

//----------#03#-----------
{ b: 12345 }[true]; //[true]

//----------#04#-----------
{ b: 12345 }["b"]; //evaluates to ["b"] ?!?

//----------#05#-----------
{ b: 12345 }.b; // "Unexpected token ."

//----------#06#-----------
({ b: 12345 }).b; //12345

//----------#07#-----------
var c = { b: 12345 }.b; 
      console.log(c); //12345

//----------#08#-----------
var c = { b: 12345 }["b"];
      console.log(c); //12345

//----------#09#-----------
{ true: 54321 }[true]; // "SyntaxError: Unexpected token : "

//----------#10#-----------
var d = { true: 54321 }[true]; //No error here ¬¬
      console.log(d); //54321

//----------#11#-----------
!{}[true]; // true

Tamam, bu çılgın davranışları birer birer anlamaya çalışalım:

1) Burada, {}boş bir kod bloğu olarak ayrıştırılır. Bir atama, olumsuzlama, gruplama (parantezlerle) veya ayrıştırıcıya bunun {}bir nesne değişmezi olduğunu belirten herhangi bir sözdizimi olmadan , varsayılan varsayım, bunun sadece işe yaramaz bir boş blok olduğunu düşünmektir.

Bu, bu davranışın bir kanıtıdır:

{ alert(123) }[true]

Yukarıdaki kod normal uyarı gösterir ve şekilde değerlendirilecektir [true]Aynı şekilde, {}[true]bir.

Noktalı Virgül İçermeyen Blok İfadeleri

Blok tipi bir ifadeden sonra noktalı virgül gerekmez.

Örneğin:

for(var i=0; i < 1; i++){}function a(){};alert("Passed here!");if(true){}alert("Passed here too!")

Her iki uyarı da gösterilir.

Böylece, noktalı virgül içermeyen boş bir blok ifadesinin geçerli olduğunu ve hiçbir şey yapmadığını görebiliriz. Bu şekilde, {}[true]Geliştirici Araçları (veya Firebug) Konsoluna girdiğinizde , değerlendirilen değer, son ifade ifadesinin değeri olacaktır . Bu durumda, son ifade ifadesi [true].

2) Bir atama bağlamında, ayrıştırıcı bunun {}bir nesne değişmezi olduğundan emin olacaktır . Var a = yaptığınızda {}[true], herhangi bir belirsizliği kaldırırsınız ve {}bir blok ifadesi olmayan ayrıştırıcıyı devre dışı bırakırsınız .
Yani burada, "true"boş bir nesneden anahtarla bir değer elde etmeye çalışıyorsunuz . Açıkçası, bu anahtar adına sahip bir anahtar / değer çifti yoktur. Bu şekilde, a değişkeni tanımsızdır.

Nesne anahtarları olarak ayrılmış kelimeler

ECMAScript 5 , nesne anahtarlarının ayrılmış sözcükler olmasına izin verir. Dolayısıyla, aşağıdaki anahtarlar yasaldır:

var obj = {if: 111, for: 222, switch: 333, function: 444, true: 555}

3) Örnek 1'in aynı açıklaması . Ama ... { b: 12345 }Parça bir blok deyimi olarak değerlendirilirse, ifadenin türü nedir b: 12345?

... (?????)

Bu bir etiket ifadesi , daha önce görmüştünüz ... Döngülerde ve içinde kullanılıyor switch. Etiket ifadeleriyle ilgili birkaç ilginç bağlantı şunlardır: 1 , (2) [ Javascript'teki iç içe döngülerden kurtulmanın en iyi yolu? , (3) [ JavaScript'te iç içe döngüler nasıl kırılır? .

NOT: Bunu değerlendirmeye çalışın:

{a: 1, b: 2} //=>>>SyntaxError: Unexpected token :

Etiket ifadeleri virgül operatörüyle ayrılamaz, bunları bir noktalı virgülle ayırmanız gerekir. Yani bu geçerli:{a: 1; b: 2}

4) Örnek 1 ve 3 için açıklamalara bakınız ...

5) Bir kez daha, { b: 12345 }bir kod bloğu muamelesi gören bir varlığımız var ve nokta gösterimini kullanarak bir kod bloğunun bir özelliğine erişmeye çalışıyorsunuz ve tabii ki buna izin verilmiyor ve ayrıştırıcı bir "Unexpected token :"istisna atıyor .

6) Kod yukarıdaki örnekle hemen hemen aynıdır, ancak ifadeyi ifade gruplama operatörü{ b: 12345 } ile çevreleyerek ayrıştırıcı bunun bir nesne olduğunu bilecektir. Bu şekilde, mülke normal olarak erişebileceksiniz ."b"

7) Örnek 2'yi hatırlayın, burada bir atamamız var, ayrıştırıcı bunun { b: 12345 }bir nesne olduğunu biliyor .

8) Yukarıdaki örnekle aynıdır, ancak nokta notasyonu yerine burada köşeli parantez gösterimini kullanıyoruz .

9)"identifier: value" Bir blok ifadesinin içindeki bu sözdiziminin bir etiket olduğunu söylemiştim . Ancak, bir etiket adının ayrılmış bir anahtar kelime olamayacağını da bilmeniz gerekir (nesne özellik adlarının tersi). Adlı bir etiketi tanımlamaya çalıştığımızda "true", bir SyntaxError.

10) Yine, bir nesneyle uğraşıyoruz. Burada ayrılmış kelimeleri kullanmakta sorun yok. =)

11) Son olarak, şuna sahibiz:!{}[true]

Buradaki şeyleri ayıralım:

a) olumsuzlamasıydı yaparak, bu ayrıştırıcı bilgisini veriyoruz {}olan bir nesne .

b) Örnek 2'de gösterildiği gibi , bir {}nesnenin adı verilen bir özelliği yoktur true, bu nedenle bu ifade olarak değerlendirilecektir undefined.

c) Nihai sonuç, undefineddeğerin olumsuzlanmasıdır . Javascript , implicity türü dönüşümü gerçekleştirir ve undefineddeğer yanlıştır .

d) Yani, olumsuzlama false... true!

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.