JavaScript has a tendency to do strange things, particularly when faced with operations on dissimilar types. This document is not meant to be a comprehensive list of undefined behavior, but rather a demonstration of the possibilities. These are not necessarily wrong (in fact, these results can be explained by the specifications), but are nevertheless odd.
Note: throughout this text, input to the JavaScript interpreter is shown with a > prompt, and the result is shown below; identical to the format of the JavaScript console in many browsers. Comments are inserted into the code blocks with JavaScript comment syntax //
. Additionally, these expressions have been evaluated in a variety of browsers, but this behavior may vary by browser and/or platform.
The +
can concatenate or add, but sometimes strange behavior occurs.
> {} + {}
NaN
> {} + []
0
> [] + {}
"[object Object]"
> [] + []
""
> [] + 1
"1"
> null + undefined
NaN
Some typeof
behavior. The built-in function typeof
returns a string representing the type of its argument.
> typeof(null)
"object"
> typeof(NaN)
"number"
Sometimes, an expression seems to be one type, and putting it in typeof
gets us something else entirely:
> {} + []
0 // the number zero, _not_ a string
> typeof({} + [])
"string" // huh?
Also, if null
is an object, as stated by typeof
, then the following makes no sense:
> 2*{}
NaN // okay, this makes sense
> 2*null
0 // this doesn't
> null + 2
2
> (null+1)/null
Infinity
typeof
said that null
was an object. Now null
is behaving like the number 0
!
More mathematical expressions. In many cases, an empty array []
behaves like zero, and sometimes an object behaves like zero. Additionally, subtracting strings works just fine, and negative zero exists:
> [] - []
0
> [] - {}
NaN
> {} - []
0
> {} - {}
NaN
> []/2
0
> 1/[]
Infinity
> []-1
-1
> {}-1
-1
> "1" - "1"
0
> -0
-0
> -[].length
-0
> -0 * 0
-0
> null*null
0
> []%true
0
Wrapping an expression involving an object in parentheses can change the value:
> {}+1
1
> ({}+1)
"[object Object]1"
> {}-1
-1
> ({}-1)
NaN
Equality is also fun, the ==
and !=
operators perform type coercion:
> 0 == ''
true
> false == '0'
true
> ' \t\r\n ' == 0
true
> undefined == null
true
Comparisons may disagree with equality:
> null > 0
false
> null < 0
false
> null >= 0
true
> null <= 0
true
> null == 0
false
> null === 0
false
Similarly, with undefined
:
> null > undefined
false
> null < undefined
false
> null >= undefined
false
> null <= undefined
false
> null == undefined
true
> null === undefined
false
A simple usage example. The golden ratio:
> ((0 == '') + Math.sqrt((-([]-true) + [] + null*null)/-(-true-true)))*([]+((' ' == 0) - '0'))/(-([]-true-[]-true))
1.618033988749895
Granted, it's a mess, but we can do better. An approximation of pi, without any alphanumerics:
> ((-!''-!!'|'-!'')+[]+(([]+((''=='')*!({}-{}))+([]-[]))/((!!'"')+!''))*((!'' + !!'')+[]+(!'' + !'.')))/((-!''+!'\\')+[]+(!''+[]/([]+(!!"'"+([]-[]))))+((!'' + ([]-[]))+(!!{}*!![])+(!''*!('"'=="'"))))
3.1415929203539825
This is done by creating the approximation of pi, 355/113, with a whole lot of operator abuse.
With a function and some loops, we can approximate Euler's number e:
> function π(_){___=(!'');for(__=-(~'.'+~'.');__<=_;__++)___*=__;return ___};____=-(!(~~{})+~!'');for(ß=-~[];ß<((!!"~"+!!'/')+[]+(!''+!"'"))*-(~[]+~{});++ß)____+=(!''*!"")/π(ß);____;
2.7182818284590455
Valid variable names in JavaScript obey a strange set of laws. In particular, a large number of Unicode characters can be used without any trouble. This handy tool is great for checking if a given character sequence is valid.
Using a loop to approximate the reciprocal Fibonacci constant:
> µ=[],µ[-(-[])]=-(-[]-!''),µ[[]-!!'~']=''*'',Ω=''/!!'\\';for(π=!!"'"*!!'"';π<((!(''/'')+~~(""/""))<<(!([]/[])+!(-~{}/[]))<<(-(~[]|{}))<<(-~{}))+[]+""*"";µ[π]=µ[π+[]-!'']+µ[π+~'~'-(-~'~')],Ω+=((''^!'')/µ[π+~[]&~[]]),++π)Ω;
3.359885666243178