

Zeros in JavaScript - co_pl_te
http://zero.milosz.ca

======
TheLoneWolfling
Wait, am I reading this right?

[1] == [1] is false, but [1] == 1 and 1 == [1]?

[0] == [0] is false, but [0] == '0' and '0' == [0]?

[] == [] is false but [] == 0 and 0 == []?

NaN === NaN is false?

[0] + [0] = '00', but [0] * [0] = 0?

Who designed this crazy language? It seems to take every quirk of every other
language and combine them in the weirdest way possible.

[] == [] is false, so it must be comparing pointers, right? Common gotcha of
Java, etc.

...Wait, NaN === NaN is false.

~~~
kevincennis
Another fun thing about NaN is that typeof NaN === 'number'. Which, you
know... seems counterintuitive based on the fact that NaN means " _Not_ a
number".

~~~
Dylan16807
Eh. 'number' means 'IEEE 754 floating point value' and NaN is certainly one of
those. Abbreviations are tricky.

~~~
kevincennis
Yeah, I understand _why_. I was just pointing out that on the surface, it
seems kind of weird.

------
ElongatedTowel
As a Pythonista Javascript is really strange. Let's combine two arrays with a
+ b. Wait, why is it now a string? Why did it just create a undefined.jpg when
I run filename + '.jpg'? Ah damn, I named it filepath. I guess I check if this
object is empty by comparing it to false, works for arrays right? Except it
doesn't and it doesn't work for arrays either because they might contain a 0.

The lesson is, always look for a method that does what you want.

~~~
TazeTSchnitzel
The undefined.jpg thing won't happen for variables in strict mode, it'll
error.

[].length is what you want for the second. IIRC [] isn't false in Python
either.

~~~
gjm11
[] is false in Python; so are other empty aggregates like () and {};
collection types implemented in Python typically follow the same pattern.
Thus:

    
    
      >>> if (): print "tuple"
      >>> if []: print "list"
      >>> if {}: print "dict"
      >>> if set(): print "set"
      >>> if "": print "string"
      >>> import collections
      >>> if collections.Counter(): print "counter"
      >>> if collections.deque(): print "deque"
      >>> 
    

(Observe that none of these prints anything.)

~~~
TazeTSchnitzel
Huh, I recall [] not working. Interesting.

------
lclemente
Chrome: "This page is in Haitian. Would you like to translate it?"

It might as well be.

~~~
iclelland
You can submit the error, with the option of declaring what language the page
is really in.

Unfortunately, "JavaScript" isn't in the list.

------
qwer
I honestly have no idea what's so confusing. I've been working with javascript
for over a decade and have NONE of this memorized, and I never look it up or
check it in the repl. It's simply not an issue if you're using jshint and unit
testing your code.

If you come from a static language background and you keep expecting a type-
checker will save you from doing silly things like adding arrays to strings,
you're always going to hate Javascript. It's a dynamically typed language, and
so you have to learn the quality-control tools and practices for dynamically
typed languages.

~~~
gargantuan
> If you come from a static language background and you keep expecting a type-
> checker will save you from doing silly things like adding arrays to strings,
> you're always going to hate Javascript.

Hmm funny I come from a dynamic language background and never had a problem
with the language telling me adding an empty list to an empty list should
somehow be empty string. That is batshit crazy. Those are not silly things
those are basic 101 strong type system checks that very dynamics languages
like Ruby and Python can do.

~~~
qwer
"Strong-typing vs weak-typing" is actually irrelevant. It's still an error at
run-time, and unless your quality control tools and practices actually run the
code (like unit tests do), you're not going to know about them.

As you move beyond native types, duck-typing (like in python) completely
subverts the strong type-checks anyway.

------
twerquie
So, use triple-equals when you don't want type coercion?

~~~
adambard
My favorite bit is where all of these are true:

    
    
        '1' == 1 
        '1' == [1]
        '1' == true  
        1 == [1]  
        1 == true  
        [1] == true
    

But this is false:

    
    
        [1] == [1]

~~~
TazeTSchnitzel
Why would it be true? Two different instances of an object don't equal in JS.
It compares identity, not value, when dealing with non-value types.

~~~
rdtsc
> Why would it be true?

It is funny that you are asking why would [1] == [1] possibly considered to be
true.

Let's see in a language with a sane and consistent typing system like Python:

    
    
           In [1]: [1]==[1]
           Out[1]: True
    

Ok, let's do a crazy language from Sweden also with dynamic types but which
are sane and consistent, like Erlang:

    
    
           1> [1] == [1].
           true
    

Surely it will be broken in Ruby:

    
    
             irb(main):001:0> [1] == [1]
             => true
    

Nah clearly it should be false, these crazy languages just haven't heard about
objects and identities and such.

~~~
artursapek
Why are you being a dick? He explained the difference accurately - JS compares
objects as individual objects. Arrays are objects. The other languages you
cited do not work that way.

Here's another example:

    
    
        4 == 4 // true
        a = new Number(4);
        b = new Number(4);
        a == b // false
        a == a // true
        a.valueOf() // 4
        b.valueOf() // 4
        a.valueOf() == b.valueOf() // true
    

And if this isn't clear yet:

    
    
        a = {}
        b = {}
        a == a // true
        a == b // false

~~~
rdtsc
Rather his tone of "Why would it be true?" sounded dick-ish. As in "How could
possibly one consider [1] == [1] be true, are you crazy? It should obviously
be false".

So I gave a couple of examples from other dynamic languages where the the sane
behavior is "obvious".

I am not being a dick I am saying the language is broken. Explaining the
historical context or the internal implementation of it doesn't make it
unbroken. Like one can explain why COBOL uses this construct or that and how
it came to be, doesn't make COBOL better or more appealing. One of course
might not have a choice and be stuck using it but lying to oneself about how
awesome it is, is not necessary.

> The other languages you cited do not work that way.

The don't, and I like how they work better.

Now whether one has a choice to use or not use JS is a different topic.
Usually there is no choice on the client side. But somehow extolling
Javascript typing rules as being sane, making sense, or as someone below put
it "brilliant" is a bit silly.

~~~
artursapek
No, he didn't ask it like that at all. You're putting words in his mouth
instead of reading the sentence in the context of the two sentences that
followed it, which made it a completely reasonable question.

------
kevincennis
A lot of this is sort of strange or unexpected, and that's obviously not a
good thing. But 99% of the operations in that table are ones that I would
never be doing in the first place.

`[null] + {} == 'null[object Object]'`? Okay, fine. I might not have known
that off the top of my head, but I also make it a habit not to add/concat
arrays and objects.

Unexpected type coercion is probably responsible for about 1% of the bugs I
write. It's just not that big of a deal once you learn the common cases (`'1'
== 1`, etc.)

------
PeterisP
Ugh. Many parts of javascript are nice but things like this (''==0?) make me
wish for a browser-supported language that was clean.

~~~
TheZenPsycho
like what? php? visual basic? c? java?

define "clean" and name one language in the history of computing that actually
fits that definition.

~~~
rdtsc
Python, Ruby, Dart just to name a few from the top of my head.

EDIT: removed Java, Rust and Go

~~~
TheZenPsycho
You forgot to define "clean". Also, java is in your list. Java had its chance.
it failed. did you forget that? So has Dart. how's dart doing? Rust as a web
scripting language doesn't even make sense.

~~~
rdtsc
Ok good point, removed Java, Rust and Go.

> So has Dart. how's dart doing?

Very well. It has a sane type system. Its VM is about twice as fast as V8, has
a nice IDE that comes with it.

------
DonPellegrino
...and that's why no one but brand new beginners use "==". If it was up to me,
"use strict" would turn "===" into "==" and there would be no "===".

It's too late now because it would break a lot of applications, so a new mode
might be required, like "use not-completely-broken-comparisons-by-default".

~~~
ricardobeat
CoffeeScript does that.

~~~
DonPellegrino
Yup, but CoffeeScript introduces 99 other ways for beginners to create awful
code, it's way easier to shoot yourself in the foot than with just JavaScript.
I still prefer CoffeeScript, though.

------
Segmentation
You know you're on HN when people are defending this broken aspect of
JavaScript, yet hate on the same broken aspect of PHP.

------
gavinpc
I had to laugh when I saw this. It made me think of the Joshua Bloch interview
in _Coders at Work_ :

> Seibel: I was reading _Java Puzzlers_ and _Effective Java_ and it struck me
> that there are a lot of little weird corners for a language that started out
> so simple.

> Bloch: There are weird corners, yes, but that's just a fact of life; all
> languages have them. You haven't seen a book called _C Puzzlers_. Why not?

> Seibel: Because it's _all_ puzzlers.

> Bloch: Yep. It would take up a shelf. In Java, the puzzlers are worth
> collecting precisely because you think of it as a simple language. Every
> language has its corner cases and Java has few enough that they're for the
> most part fun and interesting.

Interesting, maybe. But I hope people are not using all of these. [0]

[0] [http://tldp.org/LDP/abs/html/exit-
status.html](http://tldp.org/LDP/abs/html/exit-status.html)

------
paragraft
Reminds me of my favourite Javascript trivia question: What two values for a &
b meet the following?

> a === b

true

> Number(a) === a

true

> Number(b) === b

true

> a + b === a

true

> (1 / a) === (1 / b)

false

~~~
kevincennis
Edit: SPOILER ALERT

0 and -0.

I never knew about this until I read a shim someone wrote for Object.is().

------
jeswin
I think this is brilliant. Most programmers prefer code to be more readable
for computers than for humans. I think the problem is that we grow up with the
notion that computer programs have to be very strict, in syntax, types,
comparisons etc. Is there really such a need?

It was for a similar reason that many people used to like XHTML over HTML. Not
always because they needed to validate it, but to please the computer.

~~~
rdtsc
> Is there really such a need?

Yes.

Because programs, unless they deal with machine learning, statistics or other
intentional approximations, deal with _strict_ things.

If you put $0.5 in an account you don't expect to find $0.2 there when you
read it back or find "Hi Jim" there. You expect to find $0.5, when you seek to
byte offset 19553 in the file you expect to read starting with byte 19553 on
next read not "something in the vicinity of byte 19553".

[] + [] should not be '', never, it never makes sense, it is not brilliant it
is rather profoundly stupid.

Ok, language is broken, we established it, let's take a look at the library
functions. At least there cooler heads prevailed:

    
    
            $ node
            > [1,10,9,-3,-4].sort()
            [ -3, -4, 1, 10, 9 ]
    
    

Nope, they didn't.

~~~
lifthrasiir
My favorite library strangeness is:

    
    
        > [1, 4, 9].map(sqrt)
        [1, 2, 3]
        > ['1', '2', '3'].map(parseInt)
        [1, NaN, NaN]
    

cf. [http://stackoverflow.com/questions/262427/javascript-
arrayma...](http://stackoverflow.com/questions/262427/javascript-arraymap-and-
parseint)

------
louthy
It's almost depressing. It must have taken significantly more work to embed
these ludicrous rules when designing the language!

~~~
TazeTSchnitzel
It didn't. The coercing rules are fairly predictable.

~~~
warfangle
The coercing rules are fairly predictable, but oftentimes incomprehensible
until you understand what's happening behind the scenes.

It's one of the biggest weaknesses of JavaScript. Much bigger than callback
hell, garbage collection cycles etc.

My preferred style uses Array.prototype.join('') for string concatenation,
non-coercive equality operations, and only using the + operator when doing
math. It's a little cumbersome, but avoids ambiguity upon reading (and in the
case of string concatenation, can be faster).

~~~
ricardobeat
> and in the case of string concatenation, can be faster

myth: [http://jsperf.com/array-join-vs-string-
connect/37](http://jsperf.com/array-join-vs-string-connect/37)

~~~
FreeFull
In Firefox 25 on Linux, Array Join Nocopy seems to perform the fastest.

~~~
warfangle
Exactly. I rarely build up an array within a loop and then join it. That kind
of thing just seems dirty - use a buffer!

It's usually, e.g.,

['some string ', someVar, ' some rest of string'].join('');

------
Scaevolus
Here's the underlying rules of how "x == y" works: [http://ecma-
international.org/ecma-262/5.1/#sec-11.9.3](http://ecma-
international.org/ecma-262/5.1/#sec-11.9.3)

Weak typing and automatic coercions lead to some confusing results, but JS
fares better than PHP.

------
nkuttler
Everybody who writes JS should use something like jslint or jshint. JS has
ugly parts, but most can be avoided easily.

------
edgarvm
what does mean 0[object Object]?

------
TallboyOne
goofy plz

