JavaScript (както е ставало дума) е безспорният днешен владетел на интернет света и като такъв… често езикът е обект на шеги и закачки. И не без основание. Той си има своите слабости и несъвършенства (част от които биват решени с малки, но важни добавки, каквито дава например езикът TypeScript). Със сигурност, ако се занимавате малко или повече с код (или пък сте собственици на сайт с интереси в тази посока), знаете добре за какво става дума.
Е, сега сме се събрали, за да се позабавляваме с царя и неговите слабости. Да разгледаме 8 примера, в които JavaScript показва своите странности. Те определено ще дадат доста поводи за усмивка на по-опитните програмисти, които все още са скептични към него. Но и ще припомнят на хората, които го харесват и/или използват всеки ден, че той има своите не винаги приятни особености. И свободата, която дава на програмистите, може да се обърне срещу тях, стига само да не са достатъчно внимателни в работата си.
1. Време за банани
Най-забавното в случая е, че всеки от примерите, които ще ви дадем, можете да изпитате и в собствения си браузър, чрез който сте отворили тази страница. Достатъчно е с десен бутон да отворите помощния панел и там да отидете в конзолата, където да въвеждате и проверявате кода, който ви показваме.
И така, какви са тези банани? Искате да напишете “bakteria“ и въвеждате кода:
('b' + 'a' + + 'cteri' + 'a').toLowerCase();
И резултатът е….
banana
Доста неочаквано, нали? Е, ако пропуснете последното викане на функция (toLowerCase) текстът ще има две главни букви N… и именно там е разковничето какво се случва. Двойният плюс като оператор се опитва да превърне стринга – низа от символи след себе си в число и тъй като няма как да го направи, просто връща стойност NaN или “not a number”. Която „залепва“ за другите букви.
2. Човек != нечовек?
Ако попитате JavaScript дали един масив е… „немасив“:
[] == ![]
То езикът ще ви върне, че тази проверка е вярна. Също както и масивът, превърнат в числа:
+[] == +![]
Е, причината е следната. В този език, за да търсите пълно сходство между променливи и като тип се изисква операторът с три пъти равно – ===. Да, ако оставите само двата символа, езикът ще търси сходство, но без да сравнява типа данни. И двете страни според проверката са еднакви, защото, сведени до число, те са равни на нула.
Няма как да навлезем в дълбочина в проблема толкова набързо. Това, което е важно да знаете, е че е задължително винаги да използвате тройния оператор, за да не ви застигнат подобри изненади.
Ето и още няколко неочаквани резултата, които се базират на същата логика:
true == []; // -> false
true == ![]; // -> false
!!"false" == !!"true"; // -> true
true == "true"; // -> false
false == "false"; // -> false
И същевременно:
null == 0; // -> false
null > 0; // -> false
null >= 0; // -> true
3. Голяма бройка
Този проблем се появява по един или друг начин във всички съвременни езици за програмиране. Заради начина, по който числата се запаметяват в компютърната памет, много често се случва така, че 2 и 2… никак не прави четири.
Ако попитате JavaScript колко прави 0,2 плюс 0,1 отговорът определено не е 0,3:
0.1 + 0.2 == 0.3 // -> false
0.1 + 0.2 // -> 0.30000000000000004
Такъв тип грешки могат да бъдат много опасни, особено ако става дума за софтуер, свързан по някакъв начин с пари. Ето защо, ако ще се занимавате професионално с езика във финтех проект, определено си струва да отделите време, за да проучите темата с числата.
4. От кой сорт?
„Вградената“ в масива функция по сортиране не винаги работи така, както бихте предположили. Например, ако му подадете цифрите 1, 3 и 10, ще получите:
[10, 1, 3].sort() // -> [1, 10, 3]
Този метод превръща елементите в стрингове и сравнява стойтостите им, кодирани в UTF-16. Малко странно решение на създателите на езика, но какво да се прави. Нещата обаче бързо се оправят с добавянето на функция, която да бъде ползвана при сортирането, например:
[10, 1, 3].sort((a, b) => a - b) // -> [1, 3, 10]
5. За null-а време
Както вероятно знаете, всеки тип данни може да бъде проследен, докато се стигне до основните, базовите. Интересен пример обаче е типът null, който би трябвало да ни каже, че променливата не е получила (все още) някаква стойност, макар че е дефинирана (в противен случая тя е undefined).
Какъв тип обект ли е обаче този null? Надали бихте могли да го налучкате, типът е… обект.
По силата на всякаква логика обикновено там се побират по-сложни структури, които събират различни типове информация. И за да е объркването още по-голямо: типът е обект, но null не е инстанция на типа обект.
6. И нечислото е число
Вече споменахме този прословут NaN – стойността, която се получава, ако опитаме да превърнем неуспешно някоя единица данни в число. Какъв ли е типът на нечислото? Число (Number)!
typeof NaN // -> Number
Което същевременно… не прилича на себе си:
NaN === NaN // -> false
Освен това не прилича на нищо, с каквото и да го сравнявате, щe получите отговора false. Затова е полезно да знаете, че единственият вариант да проверите дали такава е стойността на дадена променлива, е да използвате метода isNaN().
7. Само ме повикай
Това тук дори не е толкова странно, колкото е предимство. Но пък е доста нетипично решение, ако за първи път се сблъсквате с езика: функциите могат да извикат самите себе си. Това определено е доста JS-ки подход, който издава програмистите с опит в използването на езика
(function() { alert('hello') })(); //alerts 'hello'
Синтаксисът е простичък и четлив. Получавате функция, която се извиква сама в правилен момент, освен това не може да бъде извикана другаде.
8. Дефинирай недефинираното
И така, приключваме списъка с някои от най-популярните странности с една доста характерна такава.
Стойността undefined обикновено се задава преди променливата да получи своята реална стойност. Например:
var someVar
alert(someVar == undefined) // -> true
Да, дотук всичко е нормално и това е съвсем очакваното използване на този тип.
Но ако продължим нататък:
undefined = "I'm not undefined!"
var someVar
alert(someVar == undefined) // -> false
Тоест… можем да зададем стойност дори на типа?! Доста странно. Със сигурност не ви препоръчваме да го правите, защото може да предизвика лавина от проблеми, особено в по-голям проект, в който обхватът на променливата е голям.
Дефинирай недефинируемото… философите могат само да завиждат за възможностите, които получават JavaScript програмистите. Този език определено е лесен за начинаещи, но има предостатъчно особености, които трябва да научим, преди да можем да го използваме пълноценно. А най-лесният вариант е с повече упражнения. Например: като си създавате нови проекти онлайн, а прекрасно решение в тази посока е напълно безплатният ни хостинг.