Skip to content

Latest commit

 

History

History
39 lines (25 loc) · 5.99 KB

Decoding the Bizarre Expression That Yields `fail`.hy.md

File metadata and controls

39 lines (25 loc) · 5.99 KB

JavaScript-ի զվարճալի տարօրինակությունները։ Մաս 2

Եթե մենք բրաուզերի կոնսոլում հավաքենք հետևյալ արտահայտությունը՝

(![] + [])[+[]] +
  (![] + [])[+!+[]] +
  ([![]] + [][[]])[+!+[] + [+[]]] +
  (![] + [])[!+[] + !+[]];

ապա այն կվերադարձնի "fail" բառը: Առաջին հայացքից կարող է անհասկանալի թվալ թե ինչպես է հնարավոր նման կամայական սիմվոլների հերթականությամբ, որոնցից ոչ մեկը տառ չէ, բառ ստանալ:

Այժմ փորձենք քայլ առ քայլ նայել արտահայտությունը, և պարզ կդառնա, որ այն ուղղակի սիմվոլների կամայական հերթականություն չէ, և լեզվի կանոնների համաձայն տեղի ունեցող` ներդրված մեթոդների անուղղակի կանչերի կամ օպերատորների օգտագործման արդյունքում մենք ստանում ենք շատ հետաքրքիր կոմբինացիաներ, և գործնականում կարող ենք ստանալ անգլերենի այբուբենի բոլոր տառերը։ Արտահայտությանը նայելիս առաջինը աչքի է զարնում այն, որ շատ հաճախ կրկնվում է (![]+[]) ենթաարտահայտությունը։ Տրամաբանական և մաթեմատիկական օպերատորների օգտագործման անուղղակի փոխակերպումների արդյունքում ինտերպրետատորը այն վերածում է String տիպի, նրա վրա կանչելով toString() մեթոդը։

(![]+[])․toString() -ը վերադարձնում է "false" սթրինգը, և այժմ եթե մենք նույն սիմվոլների օգնությամբ կարողանանք ստանալ 0-ից մինչև 4 թվերը, քառակուսի փակագծերի միջոցով դիմելով այդ սթրինգին, առանձին առանձին կստանանք "f", "a", "l", "s", "e" տառերը, որոնք էլ տարբեր կոմբինացիաներով կարող ենք օգտագործել բառեր կազմելու համար։

Մենք գիտենք որ "false"[0]-ն դա "f" տառն է, "false"[1]-ը՝ "a"-ն, "false"[2]"l"-ը և այդպես շարունակ։ Եվ այսպես +[] ենթաարտահայտությունը վերադարձնում է 0, քանի-որ դատարկ զանգվածի դիմաց դնելով ունար պլյուսի օպերատորը, մենք անուղղակիորեն այն վերածում ենք թվային տիպի (Number): Ինտերպրետատորը այդ փոխակերպումը կատարում է ենթաարտահայտության վրա տակից աշխատացնելով valueOf մեթոդը, այն իրականում լինում է այսպես՝ (+[]).valueOf() -> 0: Այսպիսով (![]+[])[+[]] ենթաարտահայտությունը համարժեք է "false"[0]-ին, և մենք արդեն ունենք "f" տառը։

Հաջորդը՝ +!+[] ենթաարտահայտությունը էլի ներդրված մեթոդների կանչի արդյունքում անուղղակիորեն վերածվում է 1-ի։ Եվ դիմելով (![]+[])[+!+[]]-ին, մենք ստանում ենք "false" բառի երկրորդ տառը՝ "a"-ն։

"l" տառի հետ նույնպես ամեն ինչ պարզ է, !+[]+!+[] ենթաարտահայտությունը անուղղակի փոխակերպվում է 2-ի և դիմելով (![]+[])-ին, մենք այնտեղից դուրս ենք բերում "false" բառի երկրորդ ինդեքսում գտնվող "l" տառը։

"i" տառը ստանալ մի քիչ ավելի դժվար է, քանի որ "false" բառի մեջ այդ տառը բացակայում է։ Բայց ինչպես գիտենք մեր սիրելի լեզվում ոչ մի անհնար բան գոյություն չունի, և համադրելով սիմվոլներն այս հերթականությամբ՝ ([![]]+[][]]), մենք անուղղակի փոխակերպման արդյունքում (ինտերպրետատորը տակից էլի աշխատեցնում է ([![]]+[][]]).toString() մեթոդը) ստանում ենք "falseundefined"։

Այժմ մեզ անհրաժեշտ է ստանալ 10 թիվը, որպեսզի "falseundefined" բառից կարողանանք դուրս հանել 10-րդ ինդեքսում գտնվող "i" տառը։ Իսկ դա անելը շատ հեշտ է արդեն, +!+[]+[+[]] ենթաարտահայտությունը տակից աշխատող valueOf() ներդրված մեթոդի շնորհիվ վերադարձնում է 10 թիվը։ Համադրելով ([![]]+[][]])[+!+[]+[+[]]] վերը ստացված երկու ենթաարտահայտությունները, մենք դուրս ենք բերում նաև "i" տառը։ Այսպիսով ստացվում է ՝

(![]+[])[+[]] + // "f"
(![]+[])[+!+[]] + // "a"
([![]]+[][]])[+!+[]+[+[]]] + // "i"
(![]+[])[!+[]+!+[]] // "l"

"f" + "a" + "i" + "l" - "fail"

Կարող եք փորձել ստանալ անգլերենի այբուբենի բոլոր տառերը, և կազմել տարբեր բառեր, ասենք ձեր անունը։ Սա լեզվական առանձնահատկություն է, որը պայմանավորված է JavaScript լեզվի թույլ տիպաբանությամբ, երբ տարբեր օպերատորներ օգտագործելով կարողանում եք մի շարք ոչ ակնհայտ, անուղղակի փոխակերպումներ կատարել մի տիպից մյուս տիպ։

Ուրիշ «տարօրինակությունների» ծանոթանալու համար կարող եք այցելել այս հղումով։