JavaScript ծրագրավորման լեզվի զվարճալի տարօրինակություններին անդրադառնալու առիթներ արդեն մի քանի անգամ եղել է։ Մի խումբ էնտուզիաստներ նույնիսկ կայք են ստեղծել, որտեղ ըստ տարեթվերի շատ կոկիկ դասավորել են տասնյակներով նման զվարճալի օրինակներ:
Սակայն ազնվության համար նշենք, որ դրանք իրականում տարօրինակություններ չեն, միգուցե զվարճալի են, բայց ամբողջովին տեղավորվում են JavaScript ծրագրավորման լեզվի դավանած փիլիսոփայության մեջ։ Լեզուն չափազանց հանդուրժող է տարբեր տիպերին պատկանող արժեքների օգտագործմամբ՝ երբեմն նույնիսկ անհեթեթության հասնող օպերացիաների նկատմամբ, երբ որևէ տեղ սպասում է որևէ տիպի արժեք, սակայն ստանում է ոչ այն, ինչ սպասում էր, չի դադարեցնում ծրագրի աշխատանքը, այլ փորձում է տիպերի անուղղակի վերափոխումների արդյունքում ստանալ հնարավորինս կոռեկտ արժեք, և շարունակել ծրագրի աշխատանքը։ JavaScript ծրագրավորման լեզվի որդեգրած թույլ տիպաբանության կոնցեպցիան ո՛չ լավ է, ո՛չ վատ։ Այն իհարկե լեզվին տալիս է անսահման ճկունություն՝ անհասանելի ծրագրավորման լեզուների ճնշող մեծամասնության համար, երբեմն օգնում է կրճատել գրվող կոդի ծավալը, սակայն մյուս կողմից էլ չափազանց բարձրացնում է ծրագրի անկանխատեսելի վարքագիծ դրսևորելու ռիսկը, ստիպում է կոդում մեծացնել ստուգումների քանակը, թեսթավորումը դարձնում է ավելի բարդ և ժամանակատար։ Իսկ հիմա դիտարկենք մի քանի չափազանց հետաքրքիր, զվարճալի տարօրինակություններ.
1 < 2 < 3; // true
3 > 2 > 1; // false
Իրականում վերևի առաջին օրինակում ամեն ինչ շատ պարզ է։ Համեմատության օպերատորները վերադարձնում են Բուլյան արժեք՝ true կամ false: Երբ արտահայտությունը նայում ենք ձախից աջ, ապա արտահայտության առաջին մասը՝ 1 < 2, վերադարձնում է true: Ապա արտահայտության երկրորդ մասում՝ true < 3, նույնպես վերադառնում է true, որովհետև փորձելով համեմատել Բուլյան արժեք հանդիսացող true-ն 3 թվի հետ, համեմատության օպերատորը true-ն անուղղակի վերածում է թվի, և ստանում 1։ Ինչպես հիշում ենք տիպերի անուղղակի վերափոխումները դասից, Բուլյան false-ը թվային արժեքի վերափոխվելիս դառնում է 0, իսկ true-ն՝ 1։
Երկրորդ օրինակը նույնպես փորձենք քայլ առ քայլ նայել։ 3 > 2 համեմատությունը վերադարձնում է true, ապա կատարվում է հաջորդ համեմատությունը՝ true > 1, որն էլ վերադարձնում է false, քանի-որ ինչպես նշեցինք, Բուլյան true արժեքի թվային վերափոխման ժամանակ ստանում ենք 1, իսկ 1-ը 1-ից չի կարող մեծ լինել, նրանք հավասար են, այդ իսկ պատճառով ամբողջ արտահայտությունը վերադարձնում է false:
console.log([1, 2, 3] + [4, 5, 6]); // 1, 2, 34, 5, 6
Այստեղ + օպերատորը հանդես է գալիս ոչ թե մեզ քաջ հայտնի թվաբանական գումարման, այլ որպես String տիպի հետ աշխատելու համար նախատեսված համակցման (concatenation) օպերատոր։ Իսկ համակցման օպերատորն արտահայտության ձախ և աջ կողմերում գտնվող զանգվածներն ուղղակի վերափոխում է տողային տիպի, և միացնում իրար։ Այսինքն այս «գումարման», իրականում՝ համակցման արդյունքը պատկանում է String տիպի։ Եթե այդ արտահայտության արդյունքը վերագրենք որևէ փոփոխականի, և typeof օպերատորով ստուգենք, կարող ենք դրանում համոզվել։
parseInt("fack", 16); // 4012
Ի՞նչ է կատարվում այստեղ։ Նախ վերհիշենք, թե ինչպես է աշխատում parseInt ֆունկցիան։ Սինթաքսը հետևյալն է՝
parseInt(string, radix)
;
Որտեղ string
պարամետրն այն արժեքն է, որից ֆունկցիան պետք է ստանա, առանձնացնի թիվը։ Արգումենտ տալու ժամանակ տողի սկզբի բացատներն անտեսվում են։ Եթե արգումենտը չի պատկանում String տիպի, ապա տակից կատարվող աբստրակտ toString օպերացիայի արդյունքում այն այնուամենայնիվ վերածվում է տողի։
radix
պարամետրը 2-ից 36 միջակայքում գտնվող ամբողջ թիվ է, և ֆունկցիային հուշում է, թե մենք ինչպիսի հաշվարկման համակարգ ենք ուզում օգտագործել։ Որպես սկզբնական արժեք ընդունված է տասական համակարգը, բայց սպեցիֆիկացիան խորհուրդ է տալիս անգամ տասական հաշվարկման համակարգն օգտագործելիս անպայման այն նշել, քանի-որ որոշ միջավայրերում (Օրինակ բրաուզերների հին տարբերակներում, որոնք ինչքան էլ զարմանալի թվա, դեռևս միլիոնավոր օգտագործողներ ունեն) կարող են սխալների պատճառ դառնալ։
Այժմ դիտարկենք մեր օրինակը։ Ինչպես տեսնում ենք որպես երկրորդ արգումենտ (radix) նշված է 16 թիվը, սա նշանակում է, որ մենք որպես հաշվարկման համակարգ ուզում ենք լինի տասնվեցական (Hexadecimal) համակարգը։ Այն ինչպես գիտենք բաղկացած է 0-9 թվանշաններից և լատինական այբուբենի A-F տառերից։ Այսինքն այս համակարգում 9-ից հետո գալիս է A-ն, հետո B-ն և այդպես մինչև F, որի համարժեքը տասական համակարգում 15 թիվն է։
Եվ այսպես ֆունկցիան սկսում է կարդալ "Fack" տողը, փորձելով այնտեղից տասնվեցական հաշվարկման համակարգի տրամաբանությամբ թիվ ստանալ։ Այդ համակարգում "F" տառը օգտագործվում է, ֆունկցիան անցնում է առաջ, "a" տառը նույնպես իմաստ ունի, ֆունկցիան շարունակում է աշխատանքը հասնելով "c" տառին, որը կրկին տասնվեցական համակարգում օգտագործվում է։ "k" տառ տասնվեցական հաշվարկման համակարգում չկա, այստեղ ֆունկցիան դադարեցնում է իր աշխատանքը, և վերադարձնում "Fac" տողի տասական համակարգում համարժեքը՝ որը 4012 թիվն է:
Ի դեպ նկատենք, որ այս բոլոր այսպես կոչված «տարօրինակություններն» իրականում ամբողջությամբ օրինաչափ վարքագիծ է, որը բխում է JavaScript ծրագրավորման լեզվի ոգուց և փիլիսոփայությունից։ Եվ լեզվի ստանդարտին մանրամասն ծանոթանալուց հետո մենք հասկանում ենք, որ այն ոչ թե տարօրինակ, այլ չափազանց ՅՈՒՐՕՐԻՆԱԿ, ԻՆՔՆԱՏԻՊ, ՃԿՈՒՆ և ՀՐԱՇԱԼԻ լեզու է, արժանի սիրո և ուշադրության։