{}[true]
jest [true]
i ![true]
powinno być false
.
Dlaczego więc !{}[true]
ocenia się true
?
javascript
user2430508
źródło
źródło
var o = {}; o[true] === undefined
.{}[true] === [true]
z konsoli, to dlatego, że traktuje ona{}
jako pusty blok kodu, a nie obiekt.{}
iw({})
konsoli (lub{}[true]
i({})[true]
). Ponadto, jak nikt o tym nie wspomniał, obiekt [prawda] jest oceniany jako obiekt [„prawda”].Odpowiedzi:
Uważam, że dzieje się tak, ponieważ zwykły
{}[true]
kod jest analizowany jako pusty blok instrukcji (nie literał obiektowy), po którym następuje tablica zawierającatrue
, czylitrue
.Z drugiej strony zastosowanie
!
operatora powoduje, że analizator składni interpretuje{}
jako literał obiektu, więc poniższy{}[true]
kod staje się zwracanym dostępem do elementu członkowskiegoundefined
i!{}[true]
jest rzeczywiścietrue
(taki, jaki!undefined
jesttrue
).źródło
undefined
jest fałszywy (coś, na czym często polegamy -if (obj.maybeExists) ...
), więc ma doskonały logiczny sens, że!undefined
to prawda.null
w niektórych językach, z!undefined
równościąundefined
. Tak nie jest jednak w Javascript.not undefined
(!undefined
), musi zatem zostać zdefiniowane. Jeśli coś jest zdefiniowane, jest zwykle interpretowane jakotrue
.Ponieważ
{}[true]
nie zwracatrue
, aleundefined
iundefined
jest oceniany jakofalse
:http://jsfiddle.net/67GEu/
'use strict'; var b = {}[true]; alert(b); // undefined b = !{}[true]; alert(b); // true
źródło
{}[true]
w konsoli, otrzymujesz[true]
, ponieważ{}
jest interpretowany jako pusty blok kodu, a nie obiekt. Chodzi o kontekst i niejednoznaczność{}
.{key:"value"}[1,2,3];
ocenia się również[1,2,3]
?key:
) i literał ciągu ("value"
), po którym następuje tablica. Parser nadal nie widzi literału obiektu.alert()
lubconsole.log()
lub przypisać ją do zmiennej powoduje zmianę kontekstu, dlatego, że nie zachowują się w ten sam sposób, jak wpisane na własną rękę w konsoli.Dlatego
{}[true]
ocenia do
undefined
i!undefined
jesttrue
.Od @schlingel:
true
jest używany jako klucz i{}
jako mapa skrótów. Nie istnieje właściwość z kluczem,true
więc zwracaundefined
. Nieundefined
jesttrue
, zgodnie z oczekiwaniami.Sesja konsoli ( Node.js
[0.10.17]
):> {}[true] undefined > !{}[true] true > [true] [ true ] > ![true] false >
Jednak w konsoli Google Chrome :
> !{}[true] true
Więc bez niespójności. Prawdopodobnie używasz starej wersji maszyny wirtualnej JavaScript. Dla tych, którzy potrzebują dalszych dowodów:
AKTUALIZACJA
W przeglądarce Firefox ocenia się również jako
true
:źródło
eval('{}[true]')
lub wpiszesz to do konsoli. Wtedy np. Als{}"test"
jesttest
lub nawet{key:"value"}"test"
jesttest
.{}[true];
(z;
) wraca[true]
za Ciebie, bo tutaj tak?Przyczyną zamieszania jest niezrozumienie twojego pierwszego twierdzenia:
{}[true]
jest[true]
To, co widzisz, gdy go uruchamiasz, jest wynikiem niejednoznaczności. Javascript ma zdefiniowany zestaw reguł, jak radzić sobie z takimi niejednoznacznościami, iw tym przypadku dzieli to, co widzisz jako instrukcję signle, na dwie oddzielne instrukcje.
Tak więc Javascript widzi powyższy kod jako dwie oddzielne instrukcje: Po pierwsze, istnieje a
{}
, a następnie jest całkowicie oddzielne[true]
. Drugie stwierdzenie jest tym, co daje wynik[true]
. Pierwsza instrukcja{}
jest skutecznie całkowicie ignorowana.Możesz to udowodnić, wykonując następujące czynności:
({}[true])
tj. zawijanie całości w nawiasy, aby zmusić tłumacza do przeczytania jej jako pojedynczej instrukcji.
Teraz zobaczysz, że rzeczywista wartość twojego wyciągu to
undefined
. (to również pomoże nam później zrozumieć następną część)Teraz wiemy, że początkowa część Twojego pytania to czerwony śledź, przejdźmy więc do ostatniej części pytania:
Tutaj mamy to samo stwierdzenie, ale z
!
dołączonym na początku.W tym przypadku reguły JavaScript mówią mu, aby oceniał całość jako pojedynczą instrukcję.
Odwołaj się do tego, co się stało, gdy zawarliśmy wcześniejsze oświadczenie w nawiasach; mamy
undefined
. Tym razem skutecznie robimy to samo, ale stawiamy!
przed tym. Więc twój kod może zostać uproszczony jako!undefined
, który jesttrue
.Mam nadzieję, że to trochę wyjaśnia.
Jest to złożona bestia, ale lekcja, której należy się tutaj nauczyć, polega na używaniu nawiasów wokół instrukcji podczas oceny ich w konsoli, aby uniknąć takich fałszywych wyników.
źródło
{}[true]
jest dokładnie nieważne , po prostu niejednoznaczne . Można go interpretować jako „pusty blok kodu, po którym następuje literał tablicy” lub „literał obiektowy bez właściwości, do których uzyskiwany jest dostęp”. Nie wiem, czy pierwszy jest technicznie przypadkiem ASI (wiele języków i tak nie wstawiłoby tam średnika), ale to interpretacja kontekstowa jest sednem problemu.{}[true]
czytrue
”, powiedzieli „{}[true]
jest[true]
”, co jest jedną z dwóch ważnych interpretacji niejednoznacznego stwierdzenia.{}[true]
jestundefined
. Aby to znaleźć, napisz to:a = {}; a[true] === undefined // true
lub po prostu:
({})[true] === undefined // true
Wiemy, że
!undefined
to jesttrue
.Z odpowiedzi @Benjamina Gruenbauma :
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; }
with ((window && window.console && window.console._commandLineAPI) || {}) { {}+{};// <-- This is your code }
Więcej informacji można znaleźć w tym pytaniu .
źródło
Odpowiedzi tutaj są dobre, oto podział pseudokodu:
{}['whatever']
= pusty blok, NewArray ('cokolwiek') = NewArray ('cokolwiek'){}[true]
= pusty blok, NewArray (true) = NewArray (true)!{}['whatever']
= LogicalNOT (convertToBool (NewObject.whewhere)) = LogicalNOT (convertToBool (undefined)) = LogicalNOT (false) = true({}['whatever'])
= Grupowanie (NowyObiekt.cokolwiek) = Grupowanie (niezdefiniowane) = niezdefiniowaneźródło
Dzieje się tak, ponieważ
{}
w twoim rozumieniu nie jest to dosłowna prezentacjaObject
, ale pusty zakres (lub pusty blok kodu):{ var a = 1 }[true] // [true] (do the same thing)
Po prostu ocenia kod w zakresie, a następnie pokazuje twoją tablicę.
I od twojego
!{}[true]
Po prostu konwertuje do int w tym zakresie i zwraca tę samą tablicę true. W tym kodzie nie ma sprawdzeń typu bool.
A jeśli spróbujesz sprawdzić wynik od
{}[true]
Ciebie, otrzymaszfalse
:{}[true] -> [true] -> ![true] -> false
Ponieważ nie ma już żadnego zakresu.
Więc
!
w swoim pytaniu zrób to samo, co:!function() { //... }
źródło
var x = {}; x[true]
.!
jest to interpretowane jako pusty obiekt, a nie zakres, i to jest rozbieżność.{}
jest obiektem bez właściwości.[]
bezpośrednio następuje po obiekcie, oznacza to „Uzyskaj dostęp do właściwości o tej nazwie”, a nie „Utwórz tablicę”true
jest wartością logiczną, ale jest używana jako nazwa właściwości, więc jest rzutowana na ciąg ("true"
)true
(ponieważ nie ma żadnych właściwości), więc{}['true']
jestundefined
!undefined
rzutujeundefined
na wartość logiczną (false
)false
wtrue
.źródło
{}[true]
(bez innego związku){}
jest nie przedmiot bez właściwości, to pusta kodu.Nie odwracasz tego wartości.
![true] != [!true]
Sprawdź to: dlaczego jest to prawda? „false”: „true” zwraca „true”?
źródło
Zagrajmy trochę więcej!
Po pierwsze, zabawmy się !:
//----------#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
Ok, spróbujmy po kolei zrozumieć te szalone zachowania:
1) Tutaj
{}
jest analizowany jako pusty blok kodu. Bez przypisania, negacji, grupowania (z nawiasami) lub jakiejkolwiek składni, która wskazuje parserowi, że{}
jest to literał obiektowy, domyślnym założeniem jest myślenie, że jest to po prostu bezużyteczny pusty blok.Oto dowód takiego zachowania:
{ alert(123) }[true]
Powyższy kod pokaże alert normalnie i zostanie oceniony jako
[true]
, w ten sam sposób{}[true]
.Instrukcje blokowe bez średników
Instrukcja typu blokowego nie potrzebuje po niej średnika.
Na przykład:
for(var i=0; i < 1; i++){}function a(){};alert("Passed here!");if(true){}alert("Passed here too!")
Wyświetlane są oba alerty.
Widzimy więc, że pusta instrukcja blokowa bez średnika jest ważna i po prostu nic nie robi. W ten sposób, gdy wejdziesz
{}[true]
do konsoli narzędzi programistycznych (lub Firebug), oszacowana wartość będzie wartością ostatniej instrukcji wyrażenia . W tym przypadku ostatnią instrukcją wyrażenia jest[true]
.2) W kontekście przypisania parser upewni się, że
{}
jest to literał obiektu. Kiedy robisz var a ={}[true]
, usuwasz wszelkie niejednoznaczności i przechylasz parser, który{}
nie jest instrukcją blokową.Więc tutaj próbujesz uzyskać wartość za pomocą klucza
"true"
z pustego obiektu. Oczywiście z tą nazwą klucza nie ma pary klucz-wartość. W ten sposób zmienna a jest niezdefiniowana.Zarezerwowane słowa jako klucze obiektów
ECMAScript 5 pozwala, aby klucze obiektów były słowami zastrzeżonymi. Tak więc następujące klucze są legalne:
var obj = {if: 111, for: 222, switch: 333, function: 444, true: 555}
3) To samo wyjaśnienie przykładu 1 . Ale ... Jeśli
{ b: 12345 }
część jest traktowana jako instrukcja blokowa, jaki jest jej typb: 12345
?... (?????)
To instrukcja etykiety , którą już widzieliście ... Jest używana w pętlach i w
switch
. Oto kilka interesujących linków dotyczących instrukcji etykiet: 1 , (2) [ Najlepszy sposób na przerwanie zagnieżdżonych pętli w JavaScript? , (3) [ Jak przerwać zagnieżdżone pętle w javascript? .UWAGA: Po prostu spróbuj to ocenić:
{a: 1, b: 2} //=>>>SyntaxError: Unexpected token :
Instrukcje etykiet nie mogą być oddzielane przecinkiem , należy je oddzielić średnikiem. Więc to jest ważne:
{a: 1; b: 2}
4) Zobacz objaśnienia do przykładów 1 i 3 ...
5) Jeszcze raz, mamy
{ b: 12345 }
istnienie traktowane jako blok kodu, a ty próbujesz uzyskać dostęp do właściwości bloku kodu za pomocą notacji z kropką i oczywiście jest to niedozwolone, a parser zgłasza"Unexpected token :"
wyjątek.6) Kod jest prawie identyczny z powyższym przykładem, ale otaczając
{ b: 12345 }
instrukcję operatorem grupowania wyrażeń , parser będzie wiedział, że jest to obiekt. W ten sposób będziesz mógł"b"
normalnie uzyskać dostęp do nieruchomości.7) Zapamiętaj przykład 2 , mamy tutaj przypisanie, parser wie, że
{ b: 12345 }
jest to obiekt.8) Identycznie jak w powyższym przykładzie, ale zamiast notacji z kropkami używamy tutaj notacji z nawiasami .
9) Powiedziałem już, że ta
"identifier: value"
składnia wewnątrz instrukcji blokowej jest etykietą. Ale musisz też wiedzieć, że nazwa etykiety nie może być zastrzeżonym słowem kluczowym (przeciwieństwo nazw właściwości obiektów). Kiedy próbowaliśmy zdefiniować etykietę o nazwie"true"
, otrzymaliśmy plikSyntaxError
.10) Ponownie mamy do czynienia z obiektem. Nie ma problemów ze słowami zastrzeżonymi. =)
11) Wreszcie mamy to:
!{}[true]
Oddzielmy rzeczy tutaj:
a) Wykonując negację, informujemy parser, że
{}
jest obiektem .b) Jak pokazano w przykładzie 2 ,
{}
obiekt nie ma właściwości o nazwietrue
, więc to wyrażenie będzie obliczane doundefined
.c) Ostatecznym wynikiem jest negacja
undefined
wartości. JavaScript wykonuje niejawną konwersję typu , aundefined
wartość jest fałszywa .d) A więc negacja
false
jest ...true
!źródło