2017-05-28 60 views
6

Mam trochę zaciemnionego kodu JavaScript. Próbowałem to zrozumieć, i robiąc to, wpisałem fragmenty w konsoli. Nie mogę zrozumieć, dlaczegoDlaczego to wyrażenie jest ocenione jako "a" w JavaScript?

> ((!!+[]+"")[+!![]]) 
< "a" 

Dlaczego ((!!+[]+"")[+!![]]) równa "a" w JavaScript? Czy są jakieś inne fragmenty kodu, aby uzyskać inne litery?

Chyba ma to coś wspólnego z automatycznym odlewaniem.

+4

To wszystko można uprościć do '("false"[1])'. Teraz wiesz, dlaczego wynik jest "a". – abhishekkannojia

+0

a jest drugą literą fałszu. Clever ^^ – WayToDoor

+2

[patrz tutaj] (https://github.com/aemkei/jsfuck/blob/master/jsfuck.js) –

Odpowiedz

6
((!!+[] + "") [ +!![] ]) 
(( !!0 + "") [ +true ]) 
((false + "") [ +true ]) 
(( "false" ) [ 1 ]) 
(  "false"[1]  ) 
(   "a"   ) 

Czy istnieją jakieś inne fragmenty kodu, aby inni litery?

Można grać z tą samą koncepcję, aby wszystkie litery z „true”, „false”, „nieokreślony”, „NaN” ...

+1

To jest właściwa odpowiedź. – SVSchmidt

+1

Dlaczego '+ []' jest równe 0? Domyślam się, że konwertuje pustą tablicę na liczbę, więc dlaczego nie 0 ... ale to zasługuje na małą linię, myślę ... i lepiej niż przypuszczam, jeśli to możliwe :) –

+0

@HuguesMoreau unary plus operacja '+' parsuje '[ ] 'na numer typu – pomber

4

Należy pracować nad pierwszeństwa operatora i typu odlewów w JavaScript:

!!+[] // Is falsey. this is same for !!+0 or !!+"" 
false + "" // Is "false". as 5+"" is "5". 

![] // Is falsey. 
!false // Is true 
+true // Is equal to 1. +[] = 0, +false = 0 

A przynajmniej

"false"[1] // Is "a" 
+2

Czy masz dobre referencje dla pierwszeństwa operatorów w JavaScript? –

+0

Dokumentacja mozilla jest wystarczająco dobra, wierzę. zawsze tam polecam. https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Operator_Precedence#Table – marmeladze

4

Użyjmy konsolę dostać naszą odpowiedź zakładając, że nie wiemy, co to znaczy, wpisując

[] + "" w wyjściach konsoli ""

tylko wprowadzenie (!!+[]) powraca Boolean false. Jeśli dołączysz wartość Boolean false do "", otrzymasz String false ze względu na typ przymusu.

Zgodnie z oczekiwaniami, wpisanie powoduje wysłanie "false" do konsoli.

Idąc dalej, w JavaScript, możesz myśleć o ciągach takich jak tablica znaków i możesz uzyskać dostęp do ich postaci za pomocą notacji tablicowej.

Tak więc w ((!!+[]+"")[+!![]]) można usunąć najbardziej zewnętrzne klamry, aby wyglądało na prostsze. Teraz mamy (!!+[]+"")[+!![]], w której pierwsza część w () zwraca Ciąg "false", a następna część w [] uzyskuje dostęp do znaku Ciągu "false". Możesz teraz postawić zakład, że +!![] w jakiś sposób zwraca 1, ponieważ "false"[1] jest równy "a".

Teraz dowiedzieć się, jak +!![] równa 1:

[] jest pustą tablicą, które można myśleć jako 0 co byłoby true w JavaScript (bo „w niczym JavaScript«prawdziwy»jest true) , więc! [] jest false i !![] jest true.

Teraz pozostaje nam +true, który jest skrótem do konwersji true na numer, który byłby 1.Teraz możesz zobaczyć, jak +!![] ocenia się na 1 i rozumiesz (miejmy nadzieję), jak działa ten zaciemniony fragment kodu!

3

Kluczem do zrozumienia tego jest wiedza, że ​​JavaScript wykonuje niejawne konwersje typów do evalute wyrażeń, które widzi. Innymi słowy, chociaż możesz nie wiedzieć, co to znaczy dodawać liczby do łańcucha znaków, JavaScript raczej zgadnie niż wyśle ​​błąd. Jest to sprzeczne z tym, co dostałeś w C++, co daje wyraźny błąd w tym przypadku.

Na przykład +x zawsze odpowiada liczbie, bez względu na to, jaki jest typ x. To samo dla !x. Dlatego dla wyrażenia:

// A: !!+[]+"" which is evaluated like !(!(+[]))+"" 
+[]  === 0 
!0  === true 
!true  === false 
false+'' === 'false' 

// B: +!![] which is evaluated like +(!(![])) 
![]  === false 
!false === true 
+true  === 1 

otrzymujemy A[B] który jest po prostu 'false'[1] === 'a'.

Możesz dowiedzieć się więcej o implicit type conversions i operator precedence na MDN.

Konwersje typów niejawnych powodują, że doświadczeni programiści JavaScript wolą używać === niż == podczas porównywania wartości.

2

Oto szczegółowy krok po kroku proces, co się dzieje:

(!! +[] + "") [ +!![] ] 
// ^^^ 

+[] Jednoargumentowy oraz na tablicy dosłownym działa, co jest równoważne Number([]) co skutkuje 0. See this dlaczego to ocenia na 0.

(!! 0 + "") [ +!![] ] 
//^^^^ 

!!0 odpowiada !!Boolean(0)) które ocenia się false od 0 jest wartość falsy.

(false + "") [ +!![] ] 
//^^^^^^^^^^^ 

false+"" jest prosty ciąg konkatenacji ocenia zatem "false"

"false" [ +!![] ] 
//   ^^^^ 

!![] jest równoważne !!Boolean([]) a od Boolean konwersja obiektów zwraca zawsze prawdziwe. To oznacza true.

"false" [ +true ] 
//  ^^^^^ 

+true odpowiada Number(true) które ocenia się 1.

"false" [ 1 ] 

który ostatecznie a.

Kluczowym punktem w tym miejscu jest Javascript, który dokonuje niejawnej konwersji typu lub typu Coercion podczas oceny wyrażeń. Aby dowiedzieć się więcej na temat przymusu typu, proponuję to doskonałe źródło napisane przez dr.Axel Rauschmayer

Type Coercion