
Stranger Things, JavaScript Edition - bajcmartinez
https://livecodestream.dev/post/2020-06-03-stranger-things-javascript-edition/
======
jdlshore
This code snippets are the JavaScript equivalent of the Obsfucated C contest:
amusing for insiders, a source of smug satisfaction for language warriors, and
ultimately of no consequence to day-to-day practitioners.

There is a relatively small list of "gotchas" in JavaScript that stem from the
early days of the language. They are easily avoided. Use a linter, "use
strict," use ===, and be explicit about your type conversions.

~~~
tomcatfish
I have a bit of a hard time with you there, I like to use maps in my code and
trying to map a parser over a list of strings and getting the wrong answer is
far from 'of no consequence' to me.

I'm not saying these issues make the language unusable, but you've got to be a
bit more honest that you were if you want to be taken seriously.

~~~
jdlshore
"If I want to be taken seriously?" Was that bit of petty oneupmanship really
necessary? I assure you, Alex, I'm completely unconcerned with whether you
take me seriously.

You were probably just trying to show off. But in case you weren't, here's how
JS works.

In JavaScript, if you're passing in a function as a parameter, the normal way
is to use an arrow function. Like this: `array.map((element) =>
yourFunction(element));`. This gives you explicit control over which
parameters are passed in to your function and how.

As a shortcut, you can provide a function _name_ rather than an arrow
function. If you do so, you're saying that you want all parameters to be
passed to that function. You're expected to know what those parameters are and
how the function you're passing in will use them. If you don't know that,
well, you're programming blind and bad things will sometimes happen. Maybe
don't do that.

As with many things in JavaScript, it's better to be explicit than rely on the
shortcut.

Edit: Just to be clear, here's the correct way to map an array of strings to
an array of numbers in JavaScript: `array.map((s) => parseInt(s, 10));`

~~~
tomcatfish
It wasn't meant to be oneupmanship, just that you were deliberately ignoring
the core of the argument. I could make an article about why NULL in C is a
wonderful feature and how it allows such nice optimizations, or I could
acknowledge that it has a great cost too. You basically said "There's no
downside if you are as smart and experienced as me", but with respect to
Javascript, much of the world (myself included) are not. Your argument came
down to "people with sufficient skill don't make this mistake", which was
definitional instead of actually addressing that the default behavior of an
actual usecase was not sane.

------
janpot
I tend to avoid parseInt unless I explicitly need a specific radix. I find the
Number function much more reliable in parsing numbers.

    
    
        ['1', '7', '11'].map(Number)
    

And if I explicitly need integers I can always filter the result

    
    
        ['1', '7', '11'].map(Number).filter(Number.isInteger)
    

It also doesn't silently parse '123thisisnotanumber' or `0x11`

------
nowandlater
Wat
[https://www.destroyallsoftware.com/talks/wat](https://www.destroyallsoftware.com/talks/wat)

------
yladiz
Say what you will about the fact that these exist in the language, I found
this post interesting because although realistically and thankfully I never
have to deal with these quirks day-to-day, it brought me more insight to the
weird nature of this language.

More specifically, the first one was quite interesting and subtle enough that
if I didn't have the `parseInt(N, 10)` rule ingrained in my head, if I had to
parse a list of numbers I would try that and then scratch my head for like 30
minutes being very confused. It's also subtle enough that I could see it
possibly going to production, because it could be missed if the code is only
lightly tested and could be missed in a code review too.

The other one that intrigued me was the second one, and I had to look up why
it works -- I didn't realize that using the + operator turns any non-parseable
value into NaN.

Thanks for the cool article!

~~~
searchableguy
I recommend people to study few things before jumping in to something complex
which will help them deal with the mess -

Understand the difference between primitive values and object values. There
are few historical bugs here with typeof that are now defined in the spec
(null, undefined etc are primitive values but will give object etc).

Floating point math:

[https://en.m.wikipedia.org/wiki/Floating-
point_arithmetic](https://en.m.wikipedia.org/wiki/Floating-point_arithmetic)

Type coercion:

[https://exploringjs.com/deep-js/ch_type-
coercion.html](https://exploringjs.com/deep-js/ch_type-coercion.html)

Prototypical inheritance:

[https://javascript.info/prototype-
inheritance](https://javascript.info/prototype-inheritance)

How this works:

[https://developer.mozilla.org/en-
US/docs/Web/JavaScript/Refe...](https://developer.mozilla.org/en-
US/docs/Web/JavaScript/Reference/Operators/this)

And you will be fine for the most part. Other things you will discover on your
own.

And use typescript if you can.

------
LandR
This article is written like these flaws in javascript are just a quirky
feature.

No, they are an embarrassment.

They don't make the language cool or interesting, they aren't tricks. They are
logically incoherent nonsense.

~~~
number6
The cooles trick in JS is that they fixed the off-by-one error using dates.
Since Month are stored in an array the 5th month is... April! How did all
other Languages get this one wrong? I don't know. That's the stuff that makes
JS cool and interesting!

------
enobrev
The solution to Scenario #1 is still going to break. As far as I'm concerned,
if you're using parseInt, you MUST explicitly define the radix. Not doing so
Will absolutely bite you in the ass.

In some cases, the parseInt rules go sideways when your number string starts
with a 0 (zero). That's going to be a rare occurrence that happens months
after you write this code, works just fine on your machine, and is going to
take days to find.

Per MDN [1]:

 _If radix is undefined, 0, or unspecified, JavaScript assumes the following:_

 _1\. If the input string begins with "0x" or "0X" (a zero, followed by
lowercase or uppercase X), radix is assumed to be 16 and the rest of the
string is parsed as a hexidecimal number._

 _2\. If the input string begins with "0" (a zero), radix is assumed to be 8
(octal) or 10 (decimal). Exactly which radix is chosen is implementation-
dependent. ECMAScript 5 clarifies that 10 (decimal) should be used, but not
all browsers support this yet. For this reason, always specify a radix when
using parseInt._

 _3\. If the input string begins with any other value, the radix is 10
(decimal)._

1: [https://developer.mozilla.org/en-
US/docs/Web/JavaScript/Refe...](https://developer.mozilla.org/en-
US/docs/Web/JavaScript/Reference/Global_Objects/parseInt)

------
vsviridov
None of those are mysteries and have been demonstrated years and years ago...
So posting clickbait...

Any engineer that allows any of the code like this in their codebase has only
themselves to blame.

------
waynesonfire
i've been reading the "professional javascript for web developers" by matt
frisbie. matt has done a great job, the book is very thorough. after reading
through about a 1/3 of the book it's evident that js is a very flexible
language and riddled with soooo many inconsistencies due to all the band-aids
manily due to the evolution of the js standard. the section of var blew my
mind. it's really sad that so many engineers are exposed to this mess. there
is a reason there are so many languages that compile to js. with this pattern,
it boggles my mind that the js standards folks continue to add more cruft into
the language. they've done enough damage.

------
colejohnson66
It doesn’t help that JS initially had no formal specification. So every
implementation had their quirks (because there were no grammar or
implementation tests).

Later formal standards created the “use strict” feature which alleviates a lot
of problems.

~~~
masswerk
In the beginning, there was just a single vendor (Netscape) and a single
implementation (Netscape Navigator). Then there was also a license and a non
compliant implentation and things became a bit weird. (E.g., missing
implementations of standard functions or missing bound checks.) However there
were definitions of the core language available from Netscape for each of the
versions, even before the ECMA standard.

------
fardeem
Everytime I think i understand JavaScript i am proven wrong. It was pretty fun
read tho

------
gitgud
Common confusion has to do with how JS overloads the "+" operator.

    
    
        '9' + 1
        = "91"
    
        +'9' + 1
        = 10
    

It's all very weird though...

~~~
SimeVidas
What would you expect string + number to do?

~~~
weare138
Kind of depends on the language. Perl converts the string to an integer if you
use a math operator on a numeric string. Python just throws an error.

~~~
erik_seaberg
When I want either addition or string concatenation, I know it, I can't think
of a use case where I'm happy getting either randomly. Perl got this right:

    
    
      2 + 2 == 4
      2 . 2 eq 22
    

You can even declare that failed conversions should throw:

    
    
      use warnings FATAL => qw(numeric)

~~~
sergeykish
Yes, perl is consistent

perl

    
    
        print "2" + 1
        3
        print "2" - 1
        1
    

js

    
    
        > "2" + 1
        "21"
        > "2" - 1
        1

------
waf
Another fun one to figure out is:

    
    
      072 === 058 // returns true
    

Thankfully, doesn't work in strict mode.

~~~
josefx
If that is a combination of octal and decimal how is 058 not a parser error?

~~~
tempodox
`072` is interpreted as octal, and `058` is interpreted as decimal (7·8+2 =
58). Ah, the dumpster fire that is JavaScript.

~~~
masswerk
Prefixing octal numbers by zero was a common convention. The real dumpster
fire was all those intermediate years without an octal notation in strict
mode. (If you needed them, either forget strict mode, or choose between
converting to meaningless decimals or using strings and feeding them through
parseInt. What's sane about this?)

However, 058 should have been a parse error.

~~~
tempodox
I agree. That inconsistency in how the `0` prefix is handled shouldn't exist.

------
maxvu
In the second scenario, I don't think it's the pre-increment operator that's
shown but the unary-plus.

------
bajcmartinez
Either you love it or you hate it, there's no middle ground with JavaScript

~~~
recursive
I used to hate it. Now I'm meh. I'm on the middle ground!

~~~
brlewis
I'm with you, but I think the parent comment is right. Because generally
comments here are either over-criticizing or over-defending JS.

~~~
karatestomp
The language has finally achieved "meh" status if you can use only the latest
version and ignore at least half of it completely. This may or many not still
make it very bad or entirely fine depending on one's perspective.

------
sproketboy
" ['1', '7', '11'].map(parseInt);

For what you would expect the output to be:

[1, 7, 11]

However, things get a bit off here, and the actual result is:

[1,NaN,3]

At first, this may look up very weird, but it actually has an elegant
explanation. "

The elegant explanation is that JavaScript was taken over by psychopaths like
bajcmartinez.

JavaScript is fine for button onClick code. Outside of that it's garbage.

~~~
zdragnar
parseInt has an optional second argument. map provides two arguments. Why is
this an example of psychopathic design?

~~~
bajcmartinez
it's just something unexpected that can happen because of the way you can pass
functions as callbacks. I liked this example because the result looks really
weird, and it can really happen to anyone, it's a mistake you can easily make
and can go unnoticed.

------
29athrowaway
JavaScript is the upside down.

------
5cott0
[https://en.wikipedia.org/wiki/JSFuck](https://en.wikipedia.org/wiki/JSFuck)

