DEV Community

Ben Halpern
Ben Halpern Subscriber

Posted on

What is the oddest JavaScript behavior?

JavaScript is notorious for its inconsistencies in a lot of areas. It's also powerful and popular and has a lot going for it.

But can we poke fun at weird things? (whether or not the behavior is a good thing in general)

Let's start with an example:

+'a' resolves to NaN ("Not a Number") because it coerces a string to a number, while the character a cannot be parsed as a number

document.write(+'a');
To lowercase it becomes nan.

Adding NaN to "ba" turns NaN into the string "NaN" due to type…

Oldest comments (85)

Collapse
 
xowap profile image
RΓ©my πŸ€–

Without a doubt I'll say this: jsfuck.com/

Collapse
 
deciduously profile image
Ben Lovy

check out the source for a full list of the nonsense they leverage. I feel like "explain each line of this file to yourself" is probably a pretty good JS litmus test.

Collapse
 
ohryan profile image
Ryan

My work firewall thinks this is porn.

Collapse
 
yorodm profile image
Yoandy Rodriguez Martinez

Ryan, HR needs to now why you're searching for programmers porn during work hours

Thread Thread
 
ohryan profile image
Ryan

Clearly :D

Collapse
 
sebastian_scholl profile image
Seb Scholl

My favorites...

alert(typeof NaN); //alerts 'Number'
alert(NaN === NaN); //evaluates false
Enter fullscreen mode Exit fullscreen mode
Collapse
 
ahferroin7 profile image
Austin S. Hemmelgarn

Most languages do this, but it could be a whole lot worse (fun fact, IEEE 754 actually allows for (2 ^ N) - 1 distinct NaN values not counting signed NaN values, where N is the bit width of the significand field in the binary representation (so for the 8-byte floats JS uses, there are 18014398509481982 possible NaN values including both signed values)).

The reason is simple, NaN is a numeric representation of a non-numeric value, so by definition it has to be the same type as numbers for the language (or, at minimum, it has to be at least one of the numeric types in the language), but you can't be certain what value it is, so you can't treat two NaN values as being identical.

Collapse
 
kspeakman profile image
Kasey Speakman

Wat is a funny talk about odd behaviors. JS starts at 1:22.

Collapse
 
elmuerte profile image
Michiel Hendriks

this is

Collapse
 
ben profile image
Ben Halpern

Obligatory

Collapse
 
bradtaniguchi profile image
Brad • Edited

This took an hour of my life:

typeof null === 'object' //true
Enter fullscreen mode Exit fullscreen mode
Collapse
 
eliasmqz profile image
Anthony Marquez

omg thank you for your service as I really didn’t know about this.

Collapse
 
willsmart profile image
willsmart • Edited

yep, a good check for an actual object is

thing && typeof(thing)==='object'

Kind of insane they did that that.

Collapse
 
brianemilius profile image
Brian Emilius

Or
Object.prototype.toString.call(thing)

Collapse
 
sleeplessbyte profile image
Derk-Jan Karrenbeld • Edited

It's not insane. null, like nil in ruby, a singleton instance of NilClass is technically an object.

Technically an array is also an object, which is why there is Array.isArray (which has its own caveats).

Thread Thread
 
willsmart profile image
willsmart • Edited

But at least ruby is rigorously consistent OO like that.

irb(main):004:0> nil.methods
=> [:&, :^, :|, :===, :inspect, :to_a, :to_s, :to_i, :to_f, :nil?, :to_h, :to_r, :rationalize, :to_c, :tap, :public_send, :instance_variables, :instance_variable_set, :instance_variable_defined?, :remove_instance_variable, :private_methods, :kind_of?, :is_a?, :instance_variable_get, :method, :public_method, :singleton_method, :instance_of?, :extend, :define_singleton_method, :to_enum, :enum_for, :<=>, :=~, :!~, :eql?, :respond_to?, :freeze, :object_id, :display, :send, :hash, :class, :singleton_class, :clone, :dup, :itself, :taint, :tainted?, :untaint, :untrust, :trust, :untrusted?, :methods, :protected_methods, :frozen?, :public_methods, :singleton_methods, :!, :==, :!=, :__send__, :equal?, :instance_eval, :instance_exec, :__id__]

In JS there are very few object-type calls that work in any way with nulls, so it's neat that they aimed to make this aspect of the language more OO, but they should have followed through better.
typeof(null) being 'object' is seldom anything but annoying for JS devs.

eg.

> Object.getOwnPropertyNames(null)
< Uncaught TypeError: Cannot convert undefined or null to object
    at Function.getOwnPropertyNames (<anonymous>)
    at <anonymous>:1:8
> null.foo
< Uncaught TypeError: Cannot read property 'foo' of null
    at <anonymous>:1:6
(anonymous) @ VM176:1
> for (const k of null);
< Uncaught TypeError: null is not iterable
    at <anonymous>:1:17

Basically there are very few times you might write typeof(thing)==='object' where you shouldn't do the null check too

Thread Thread
 
sleeplessbyte profile image
Derk-Jan Karrenbeld

Absolutely true. I was only referring to the use of the word "insane" which just sounds very unknowing/ignorant to me.

FWIW, now that we use TS for most things, this is not problem for us often, except for when something is nullable Γ‘nd multiple types (object/number/string/undefined).

My recommendation is to never use null and only use undefined. Replace your "null"s with an "EMPTY/UN_SET" data type.

Thread Thread
 
willsmart profile image
willsmart

Fair enough. I didn't mean insane in the sense of completely without reason, just in the sense that it was badly thought out.

The thing is that nulls are now baked into JS at a few levels, so in our own code we can avoid them, but they pop up throughout the various JS apis, eg

> /a/.exec('b')
< null
> document.body.getAttribute('a')
< null

That's what I mean by the loose "insane" comment. It was a mistake that was bad enough that as JS devs we're now best off to generally avoid the fundamental null value in JS.

I totally agree with you about TS, which corrects many of these issues, and how in JS we're best to use undefined whereever possible.

Collapse
 
lukewestby profile image
Luke Westby • Edited
typeof document.all === 'undefined' // true
document.all instanceof HTMLAllCollection // true
Collapse
 
jmplourde profile image
Jean-Michel Plourde • Edited

I find these very funny:

typeof(1 + '1') // returns a string because + is overloaded to concatenate

typeof(1 * '1') // but not *

"1" -- "1" // returns 2

"1" - "1" // returns 0

Collapse
 
nijeesh4all profile image
Nijeesh Joshy

I observed a weird thing with js and started an discussion on it

dev.to/nijeesh4all/why-two-small-f...

Thanks to @da-ti for the explanation

Collapse
 
adam_cyclones profile image
Adam Crockett πŸŒ€

There is one that I can't remember precisely, but JavaScript cannot add 2.637 or something like that the result is wrong. I will have to look this up.

Collapse
 
keptoman profile image
mlaj

Adding floats. It won't give the right answer. It's a common problem in programming languages.

Collapse
 
adam_cyclones profile image
Adam Crockett πŸŒ€

Yeah I had a suspension that was the case. Still it's odd and it doesn't not affect JavaScript so I'm technically correct. πŸ™ƒ

Collapse
 
kspeakman profile image
Kasey Speakman • Edited
console.log(.3);
// 0.3

console.log(.1 + .2);
// 0.30000000000000004
Collapse
 
adam_cyclones profile image
Adam Crockett πŸŒ€

That's the one! Thanks!

Collapse
 
adam_cyclones profile image
Adam Crockett πŸŒ€

This is batshit don't you think?