{}[true]jest [true]i ![true]powinno być false.
Dlaczego więc !{}[true]ocenia się true?
{}[true]jest [true]i ![true]powinno być false.
Dlaczego więc !{}[true]ocenia się true?
{}[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ąca true, czyli true.
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łonkowskiego undefinedi !{}[true]jest rzeczywiście true(taki, jaki !undefinedjest true).
undefinedjest fałszywy (coś, na czym często polegamy - if (obj.maybeExists) ...), więc ma doskonały logiczny sens, że !undefinedto prawda.
nullw niektórych językach, z !undefinedrównością undefined. Tak nie jest jednak w Javascript.
not undefined( !undefined), musi zatem zostać zdefiniowane. Jeśli coś jest zdefiniowane, jest zwykle interpretowane jako true.
Ponieważ {}[true]nie zwraca true, ale undefinedi undefinedjest oceniany jako false:
'use strict';
var b = {}[true];
alert(b); // undefined
b = !{}[true];
alert(b); // true
{}[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()lub console.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 undefinedi !undefinedjest true.
Od @schlingel:
truejest używany jako klucz i {}jako mapa skrótów. Nie istnieje właściwość z kluczem, truewięc zwraca undefined. Nie undefinedjest true, 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:

W przeglądarce Firefox ocenia się również jako true:

eval('{}[true]')lub wpiszesz to do konsoli. Wtedy np. Als {}"test"jest testlub nawet {key:"value"}"test"jest test.
{}[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:
Dlaczego więc! {} [True] jest przeliczane na prawda?
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 jest true.
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.
{}[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]czy true”, powiedzieli „ {}[true]jest [true]”, co jest jedną z dwóch ważnych interpretacji niejednoznacznego stwierdzenia.
{}[true]jest undefined. Aby to znaleźć, napisz to:
a = {};
a[true] === undefined // true
lub po prostu:
({})[true] === undefined // true
Wiemy, że !undefinedto jest true.
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;
}
Więc zasadniczo wykonuje a
callna obiekcie z wyrażeniem. Wyrażenie to:
with ((window && window.console && window.console._commandLineAPI) || {}) {
{}+{};// <-- This is your code
}
Zatem, jak widać, wyrażenie jest ewaluowane bezpośrednio, bez nawiasów zawijających.
Więcej informacji można znaleźć w tym pytaniu .
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) = niezdefiniowaneDzieje się tak, ponieważ {}w twoim rozumieniu nie jest to dosłowna prezentacja Object, 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, otrzymasz false:
{}[true] -> [true] -> ![true] -> false
Ponieważ nie ma już żadnego zakresu.
Więc !w swoim pytaniu zrób to samo, co:
!function() {
//...
}
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ę”truejest 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!undefinedrzutuje undefinedna wartość logiczną ( false)falsew true.{}[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”?
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
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].
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.
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 typ b: 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 plik SyntaxError.
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 nazwie true, więc to wyrażenie będzie obliczane do undefined.
c) Ostatecznym wynikiem jest negacja undefinedwartości. JavaScript wykonuje niejawną konwersję typu , a undefinedwartość jest fałszywa .
d) A więc negacja falsejest ... true!
var o = {}; o[true] === undefined.