JavaScript е жена. Понякога е отзивчивата, вършеща всичко любима, а понякога е нетърпимата, правеща каквото си поиска, нелогична в действията си красавица, която ви подтиква да се влюбите в нея. Ако любовта към жената минава през стомаха, то любовта към javascript тогава минава през много F*ck this shit. Накрая просто се жените за нея и… свиквате със чудатостите и.
Целта на следващите примери са обобщение на някой известни, и някои не толкова известни поведения на js в някои browser-и, които голяма част от хората свикнали с “цивилизовани езици”, смятат за странни. Повечето примерите са базирани на поведението на JS по ECMAScript 5.1 в browser среда.
Всичко е object
Или почти всичко, като изключим примитивите (String, Boolean и т.н.), които обаче пък имат object wrapper-и, от където идва и самото объркване, че всичко в js е object.
И тук човек си мисли, да сигурно всичко е object, като изключим да речем и null. Само че дори null е object.
typeof null // results in "object"
Въпреки това, дефиницията за null е “тотална липса на смислена стойност”. Именно затова и
null instanceof Object // results in false
Така хем е обект, хем не е… та предполагам започвате да разбирате защо си позволих сравнението между js и нежния пол.
Undefined can be defined
Колкото и странно да звучи undefined, въпреки че е ключова дума в js, може да бъде дефинирана. Следния код е напълно смислен.
var pesho; pesho == undefined; // results in true
Всичко е супер, до момента до който не решим че можем да присвоим стойност на undefined.
undefined = "Test"; var pesho; pesho == undefined; // results in false;
Та въпреки че не сме дали стойност на pesho след сравнение с undefined резултата е false, просто защото преди това сме дали стойност на undefined – яко… Тази красотия се появява най – често при FireFox и най – лесно може да си дадете обяснение като отидете на сайта им и потърсите дали според тях undefined e ключова дума.
replace()
Тук, странностите са няколко. Нека да започнем с първата.
"gosho".replace("o", "a"); // results in "gasho" - the rise of a new hero
Може би очаквате replace да ви замени всички срещания на даден символ – не точно. Би могло да стане, но за целта трябва да използвате regex, което предвид “големите” regex познания при всички програмисти, прави тази функция доста приятна.
"gosho".replace(/[o]/g, "a"); // results in "gasha" - not as cool as gasho
Втората странност е възможността 2рия параметър на replace() да бъде callback. Спорно е колко често ще ви се наложи, но е добре да си имате едно на ум. Да речем в произволен текст искате да замените температурата от Фаренхайт към Целзий.
function f2c(str) { var regexTest = /(\d+(?:\.\d*)?)F\b/g; // this will search for every number that ends with F (for Fahrenheit) function convert(str, p1) { return ((p1-32) * 5/9) + "C"; } return str.replace(regexTest, convert); } f2c("Today is 60F"); // results in "Today is 15.5C"
NaN е… число
Спомняте ли си колко абсурдно звучеше, че null е object. А колко по – странно е че NaN(“Not a Number – не е число”) всъщност е число. И за да е пълна приказката – NaN не е NaN :D Всъщност NaN не е равно на нищо. Единствения начин да разберете дали нещо не е число, е не като го сравнявате с NaN а като използвате функцията isNan().
typeof NaN; // results in "number" NaN === NaN; // results in false "pesho" === NaN // results in false isNaN("pesho"); // results in true
Math.min() & Math.max()
Тази странност е по – лесна. Чисто и просто Math.min() е по – голямо от Math.max(), защото Math.min() връща +Infinity, докато Math.max() връща -Infinity.
Math.max() > Math.min() // results in false
Date
Когато Date се извиква като конструктор, връща обект, който е релативен спрямо 1 Януари 1970. Когато обаче параметър липсва, получаваме текущото време. Когато обаче извикаме Date като функция получаваме не обект, а стрингова репрезентация на текущото време.
var a = Date(); // results in string "Mon Apr 28 2014 13:33:23 GMT+0300 (FLE Daylight Time)" var b = Date(0); // again results in string "Mon Apr 28 2014 13:33:23 GMT+0300 (FLE Daylight Time)" var c = new Date(); // results in object of today - "Mon Apr 28 2014 13:34:27 GMT+0300 (FLE Daylight Time)" var d = new Date(0); // results in object of 1970 - "Thu Jan 01 1970 02:00:00 GMT+0200 (FLE Standard Time)"
Length
Някои стойности по подразбиране също могат да бъдат малко подвеждащи. Да речем дължината на Function по подразбиране е 1. Докато дължината на Function прототипа е 0.
var a = Function.length; // results in 1; var b = new Funtion().length; // results in 0;
Още за ключовите думи
Като цяло странностите с ключовите думи не са 1 и 2. Следващата която ще разгледаме е ключовата дума class. Да си представим следната ситуация:
var a = { class: "Human", name: "Gasho" }; a.class // results ???
Ако се замислим най – логичното е ако пробваме да достъпим пропъртито class на обекта а, да получим резултат “Human”. Но отново зависи от случая. Chrome, FF и Opera отчитат class като ключова дума, но го приемат като възможно пропърти (какъвто е и нашия случай). Но познайте кой browser не изброих. IE отново си имат собствено мнение. Там още декларацията ще ви гръмне със “Expected identifier, string or number”.
name
name е readonly пропърти, което всяка функция има. Интересното е, че като такова би трябвало да гърми ако се опитате да го промените. No.
function gasho() { }; gasho.name; // results in "gasho" gasho.name = "pesho"; // should throw error?? gasho.name; // results again in "gasho"
toString
Много често искате да стрингосате дадено число. Някои могат да решат, че 3.toString() е достатъчно. Само че това ще гръмне със синтактична грешка. От друга страна 3..toString() ще ви върне резултат “3”, понеже разчита 3. като 3.0, което вече стрингосано води до “3”. Естествено 3…toString() обаче също ще гръмне понеже няма число с две точки :).
Говорейки за toString един от най wtf сценариите е следният.
2 == [[[[2]]]]; // results in???
Привидно масива от масиви от масиви (и т.н.) е несравним със число. Само че в случая js ги стрингосва и 2те и така ги сравнява и резултата от сравнението е true.
Последното нещо свързано със стрингосването, на което ще обърна внимание е следния вариан:
"5" + 3; // results in 53 "5" - 3; // results in 2
Причината за това е че + оператора се използва за обединяване на стрингове и в случая числото 3 автомагически се стрингосва и се залепя до 5тицата. Докато при оператора “-” се извършва обратната операция и числата се възприемат като такива.
Математически операции
Като цяло js не е език на който можете да разчитате на точни сметки. Нито със малки, нито със големи числа.
var a = 111111111111111110000 + 1111; // results in 111111111111111110000 var b = 0.8 - 0.6; // results in 0.20000000000000007
No idea
Още един доста интересен случай. В ситуацията обаче ако трябва да съм честен и аз не съм много наясно какво точно се случва.
1 + - + + + - + 1; // results in 2
Заключение
Както виждате и сами може би javascript наистина е жена. За съжаление обаче може би обърнахме внимание само на негативните качества, докато се надявам следващия път (дано е скоро, че с това темпо на писане на постове…), ще обърнем внимание на по – сложните сценарии като ще намесим scope, arrays, constructors и т.н. и ще разгледаме защо все пак в крайна сметка се влюбваме в javascript.
Чувствайте се свободни да коментирате и странности на които вие сте попадали.
В “No idea” това, което се случва, е че математическите оператори “+” и “-” при наличие само на един аргумент считат втория за 0, т.е. все едно изразът ти е
1 + 0 – 0 + 0 + 0 + 0 – 0 + 1;
Всъщност горният коментар не е точен, просто единственият знак, който се изпълнява като оператор, е първият (+ът), а всеки следващ отдясно-наляво се прилага върху последната единица, и понеже минусите са четен брой, тя се оценява отново до 1, и накрая изразът се свежда до
1 + 1
Супер, мерси за пояснението
Благодаря ти, Павка!!!
Благодарим ти, Павка!
Принципно различните браузъри си имат допълнителна имплементация на част от нещата – за тест, “”.replace.toString() под FireFox ще издаде интересна имплементация, виж го.
Иначе, по дефиниция, ако първият параметър подаден на String.replace е string, то трябва да се замени само първият срещнат – http://www.ecma-international.org/ecma-262/5.1/#sec-15.5.4.11
Благодаря ти, Павка™!
Ето и някои от една моя лична подборка по същата тема: http://blog.marudina.net/?p=266
JavaScript e жена … свободна от предрасъдъци, поради това нелогична в “граничните задачи”, но и креативна! Не стоят ли нещата по подобен начин и с други два езика – PHP и Basic.? Креативност и жизненост срещу правилата и каноните…хубава тема за размисъл, благодаря!
Очакваме продължение с положителните страни на “жената” ;)
В добавка на казанато от Maya ако последният пример го променим леко :
1 + – + + + – – – 1 // 2
т.е. имаме четен брой оператори, последният оператор от ляво на дясно се приема като знак на числото.
Благодаря за статията.
Тя е наистина още една мотивация за моята любов към джаваскрипт.
Преди пишех на С и всичко беше толкова скучно. Оправящ една грешка, той ти казва “хайде давай, че има още 100”. Тук само го отварям, гледам кое не му е харесало, оправям го и спи града. А и най-хубавото – няма указатели – просто език мечта!
Въпрос : защо
let sentence = “This is a string”;
console.log(sentence[10]); ми връща само 1 символ ? “s” ?
Ами защото може да разглеждаме стринговете като масив от символи :) в случая десетият елемент от стринга е символа “s” (първата буква на “string”)