Movatterモバイル変換


[0]ホーム

URL:


Skip to content
DEV Community
Log in Create account

DEV Community

Cover image for JavaScript quirks in one image from the Internet
Mikhail Korolev
Mikhail Korolev

Posted on

     

JavaScript quirks in one image from the Internet

Recently I stumbled upon this picture on Google Images:

Thanks for inventing JavaScript

The man on the picture is Brendan Eich by the way, the creator of JavaScript and a co-founder of the Mozilla project.

Even with some of the examples are not really related to the language itself, I still find it interesting enough to give it a short breakdown, considering it doesn't make much sense for some people with the classic "strict language"-only programming background.

The breakdown

Starting with the "boring" parts:

Floating-point arithmetic

> 9999999999999999< 10000000000000000> 0.5+0.1==0.6< true> 0.1+0.2==0.3< false
Enter fullscreen modeExit fullscreen mode

Nothing really surprising here, it's an old concept that has been around for quite a while. And it is, of course, not related to JavaScript "features". Instead of trying to explain it here, I'll just leave a link the tothis great "explainlikeimfive" website dedicated exclusively to explaining floating-point math.

Not A Number is a Number

> typeof NaN< "number"
Enter fullscreen modeExit fullscreen mode

What is "NaN" after all? It is, in fact, a representation of a specific value that can't be presented within the limitations of the numeric type (the only JS numeric primitive is, in factfloat). NaN was introduced in the IEEE 754 floating-point standard.

So, it's just a number that a computer can't calculate in this particular environment.

Type conversion

JavaScript is a dynamic type language, which leads to the most hated "why it this like that" debugging sessions for those who is not familiar with the silent (implicit) type coercion.

The simple part: strict equality with===

> true === 1< false
Enter fullscreen modeExit fullscreen mode

Strict equality compares two values. Neither value is implicitly converted to some other value before being compared. If the values have different types, the values are considered unequal. Boolean variable is not equal to 1, which is a number.

On the other hand, there is this:

> true == 1< true
Enter fullscreen modeExit fullscreen mode

This is an example ofimplicit type coercion. Implicit type coercion is being triggered when you apply operators to values of different types:2+'2','true'+false,35.5+new RegExp('de*v\.to') or put a value into a certain context which expects it to be of a certain type, likeif (value) { (coerced toboolean).

JavaScript type conversion is not the most trivial part, so I would suggest further reading likethis great article by Alexey Samoshkin andthis little MDN doc on equality comparisons. There is also thisequality comparison cheatsheet that may come in handy.

Anyway, let's get back to our picture.

> [] + []< ""
Enter fullscreen modeExit fullscreen mode

There are 2 types of variables in JS: objects and primitives, with primitives beingnumber,string,boolean,undefined,null andsymbol. Everything else is an object, including functions and arrays.

When an expression with operators that call implicit conversion is being executed, the entire expression is being converted to one of three primitive types:

  • string
  • number
  • boolean

Primitive conversions follow certain rules that arepretty straightforward.

As for the objects: In case ofboolean, any non-primitive value is always coerced totrue. Forstring andnumber, the following internal operationToPrimitive(input, PreferredType) is being run, where optionalPreferredType is eithernumber orstring. This executes the following algorithm:

  1. If input is already a primitive, return it as it is
  2. Otherwise, input is treated like an object. Callinput.valueOf(). Return if the result is a primitive.
  3. Otherwise, callinput.toString(). If the result is a primitive, return it.
  4. Otherwise, throw a TypeError.

Swap 2 and 3 ifPreferredType isstring.

Take a look at this pseudo-implementation of the above in actual JavaScript, plus the boolean conversion (the original is acourtesy of Alexey Samoshkin via the article mentioned previously).

functionToPrimitive(input,preferredType){switch(preferredType){caseBoolean:returntrue;break;caseNumber:returntoNumber(input);break;caseString:returntoString(input);breakdefault:returntoNumber(input);}functionisPrimitive(value){returnvalue!==Object(value);}functiontoString(){if(isPrimitive(input.toString()))returninput.toString();if(isPrimitive(input.valueOf()))returninput.valueOf();thrownewTypeError();}functiontoNumber(){if(isPrimitive(input.valueOf()))returninput.valueOf();if(isPrimitive(input.toString()))returninput.toString();thrownewTypeError();}}
Enter fullscreen modeExit fullscreen mode

So, at the end of the day, the original[] + [] == "" is being interpreted as:

ToPrimitive([])+ToPrimitive([])
Enter fullscreen modeExit fullscreen mode

Both arrays return an empty string as a result oftoString([]). The final result is a concatenation of two empty strings.

Now, onto the:

> [] + {}< "[object Object]"
Enter fullscreen modeExit fullscreen mode

Because of theString({}) resulting in a[object Object] the result is a simple concatenation of"" and"[object Object]". Simple enough. Now what the hell is going on here then?

> {} + []< 0
Enter fullscreen modeExit fullscreen mode

Turns out, JavaScript interprets the first{} as a code block! When the input is being parsed from start to end, it treats{ as the beginning of the block, following by closing} immediately. Hence, using our pseudo-implementation the previous example will be evaluated into the following:

ToPrimitive(+[])
Enter fullscreen modeExit fullscreen mode

..which is 0. The+ is an unary prefix operator that converts the operand into a number.

Loose equality== and binary+ operators always trigger defaultpreferredType, which assumes numeric conversion (except Date that returns string). That explainstrue+true+true===3 andtrue==1. Thus, as expectedtrue===1 returnsfalse because there are no operators on the left side of the expression and=== does not trigger implicit type coercion. Same with[]==0 which is roughly equivalent toNumber([]) == 0.

Everything brings up interesting examples like the one we have here:

> (!+[]+[]+![]).length< 9
Enter fullscreen modeExit fullscreen mode

Breaking it down,

  • (!+[]) + [] + (![])
  • !0 + [] + false
  • true + [] + false
  • true + '' + false
  • 'truefalse'

'truefalse'.length === 9

Very simple.

And last (and the least, to be honest):

Math.max() < Math.min() ?

> Math.max()< -Infinity> Math.min()< Infinity
Enter fullscreen modeExit fullscreen mode

Thismay be considered as a minor language flaw, in terms of returning a kind of an unexpected result from a function that wants certain arguments.

But there actually is a little bit of some actual math behind that.

Let's make a guess on how (probably)Math.max() works and write down another imaginary transcript into actual #"http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24">Enter fullscreen modeExit fullscreen mode

Now it kind of makes sense to return-Infinity when no arguments are passed.

-Infinity is anidentity element ofMath.max(). Identity element for a binary operation is an element that leaves any other element unchanged after applying said operation to both elements.

So, 0 is the identity of addition, 1 is the identity of multiplication.x+0andx*1 is alwaysx. Out of-Infinity andx,x will always be the maximum number.

There is an absolutelygorgeous article by Charlie Harvey that deeply dives into this topic.


Summing up, implicit type coercion is a very important concept you should always keep in mind. Avoid loose equality. Think about what are you comparing, use explicit conversion whenever possible. Consider switching to TypeScript if the above scares you :)

And if you want to see more "wtf" JavaScript, there is a great resource called, literally,wtfjs, that is also available as a handbook vianpm.

Top comments(7)

Subscribe
pic
Create template

Templates let you quickly answer FAQs or store snippets for re-use.

Dismiss
CollapseExpand
 
thomasthespacefox profile image
Thomas Leathers
Hi, I'm Thomas, chief developer of the SBTCVM project, and all around artist and programmer. I do have more of an understanding of balanced ternary than most i would say.
  • Joined

being a python dev who writes desktop applications & games, I'm still mystified by js. its interesting though, to actually see WHY it does what it does. this is the first time ive seen javascript's flaws discussed in a way that actually makes sense,even if those flaws still make my python-centric developer brain hurt. :)

CollapseExpand
 
jacksonelfers profile image
Jackson Elfers
  • Joined

It's ironic how JavaScript continues to dominate only because we can't get rid of it in the browser. In a lot ways I wish the world ran on Python instead. 😁

CollapseExpand
 
thomasthespacefox profile image
Thomas Leathers
Hi, I'm Thomas, chief developer of the SBTCVM project, and all around artist and programmer. I do have more of an understanding of balanced ternary than most i would say.
  • Joined

because of my experience working on SBTCVM, a base 3 virtual machine inspired by 50s Russian computers, specifically its 2 custom languages, I know language design isn't necessarily easy...

Whether its a scripting language or a compiled one, its not something that goes well if you rush, nor is it easy in any sense.

as far as scripting languages, they often depend heavily on what environment they are built for, even if such dependence isn't always obvious.

On another note, compiled languages come with their own set of challenges, challenges I'm sure some braver web developers might dive into once web assembly becomes more common.

Then again, writing programs for a 6.5Khz ternary CPU emulated in python, is a tad different than scripting hypertext :p

Thread Thread
 
jacksonelfers profile image
Jackson Elfers
  • Joined
• Edited on• Edited

Sounds absolutely wild, I'd love to hear more about it. I'm looking forward to web assembly. I could see it potentially opening the flood gates for new web technologies. Best of luck with your ternary emulations. Edit: Looks like you've written quite a bit on the subject. Small typo in your bio 😁

CollapseExpand
 
crongm profile image
Carlos Garcia ★
Front end developer for the past three years, web developer (HTML &amp; CSS) for almost 10 years.Dabbles in game dev/design when life permits.
  • Location
    Mexico
  • Joined

Loved your article Mikhail. While I understood most examples and even knew how they work on the surface, your deep explanation and linked articles made me learn something new. Thank you.

CollapseExpand
 
ehsanlotfi profile image
ehsan lotfi
  • Joined

pashmam

CollapseExpand
 
detunized profile image
Dmitry Yakimenko
Grew up in Russia, lived in the States, moved to Germany, sometimes live in Spain. I program since I was 13. I used to program games, maps and now I reverse engineer password managers and other stuff
  • Location
    Berlin and Málaga
  • Education
    MS in CS from State Polytechnic University of St. Petersburg
  • Work
    Principal Software Engineer at HERE
  • Joined

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment'spermalink.

For further actions, you may consider blocking this person and/orreporting abuse

Mikhail Korolev
undefined
  • Location
    Warsaw, Poland
  • Work
    Software Engineer @ Toptal Core
  • Joined

Trending onDEV CommunityHot

Jaideep Parashar profile image
The AI Industry Has a Truth Problem: Here’s How I See It
#ai#discuss#learning#career
Ben Halpern profile image
Meme Monday
#discuss#watercooler#jokes
Anmol Baranwal profile image
I built a self-hosted Google Forms alternative and made it open source! 🎉
#opensource#programming#showdev#javascript
DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Log in Create account

[8]ページ先頭

©2009-2025 Movatter.jp