wtfwtfjs


Introduction

This is a response to the wtfjs blog. JavaScript has a lot of people criticizing it (many times correctly), but not very many people defending it.

JavaScript definitely has its quirks and irregularities, but it's also a very misunderstood language. Some of its seemingly strange behavior makes perfect sense once you realize what's really going on.

Don't take any of this too seriously, as I'm pretty sure the wtfjs people don't take it too seriously themselves. Remember, it's just the Internet. If you disagree with anything here, or want correct any mistakes (I have made a few in my life), feel free to contact me. You can also email me at "email at (my-real-name-with-no-hyphens) dot com".

Infinity

Every language that uses IEEE 754 floating point numbers (that's almost all of them) would behave exactly the same way here. 1e400 overflows 64-bit double-precision floats, so it gets turned into Infinity. Obviously, infinity - anything is still infinity.

Don't mind that zero

The zero doesn't make a difference when the string is converted to a number (which is what the == operator does in this case). Use the right operator. Nobody complains when & doesn't use short-circuit evaluation, when they really meant &&.

Firebug console WTF

Firefox (and ECMAScript 5) supports read-only properties. Firebug adds a console getter, but no setter to the window object. If you do change console (it is possible, by creating a new getter/setter pair), it breaks the Firebug console (surprise, surprise). Not a JavaScript issue, and not a WTF.

Auto Globals

I can't argue with this one. Automatic global variables are probably the single biggest WTF with JavaScript. Fortunately, ECMAScript 5 strict mode will throw an exception in this case, instead of creating a global variable.

Lexical Scope

The reason this works is that the global scope is a normal JavaScript object (the "default" value for this, and also called window in browsers). JavaScript, being the dynamic, prototypical language that it is, lets you add modify built-in objects' prototypes. Adding a property to Object.prototype, essentially adds it to all objects, including the global scope object.

This is only a WTF if putting global variables in an object and allowing programmers to modify prototypes are WTFs. I don't think either of those are bad things; they are part of what makes JavaScript so flexible and powerful. The only WTF is actually modifying Object.prototype; that's almost always a bad idea. Why would you want to add a property to every object anyway?

Number-String Equality

Yup, that's how the operator works. If you don't like it, use the preferred = operator.

This seems like complaining that code in a do-while loop runs even when the condition is false. If you use the wrong operator (or control structure), you get the wrong behavior.

setTimeout

This isn't really a JavaScript issue, it's just a difference in Firefox's implementation of the setTimeout function, but I'll cover it anyway.

The description on wtfjs.com explains, correctly, that the "rand" parameter is really telling you how late the function call was. I'm not sure how a function behaving exactly how it was designed to is a WTF. Unfortunately, for a long time it wasn't documented, and no other browsers implemented the same functionality. If you don't want Firefox to clobber your default parameters, don't pass it a function that expects any arguments (you can wrap a function call in an anonymous function if you need to).

Variable hoisting

This one makes perfect sense as long as you remember that JavaScript has function-scoped variables. The variable is in scope for the entire function just like always. Of course, the initialization still happens when you tell it too. The example actually just re-initializes window to undefined, so the order of the statements in this case doesn't affect anything.

WTFJS undefined

Yes, undefined is a variable. Yes, it would probably be better as a constant (it will be in ECMAScript 5). To me, this is equivalent to the following code:

JavaScript is a dynamic language. It lets you mess with it's built-in objects. Just remember: with great power comes great responsibility.

Arrays are true

This one, I kind of agree with, because it's not intuitive (another reason to prefer the = operator in most cases). To further explain what's going on, the right side (![]) converts the array to a boolean (true) and flips it to false. Then the operator, since the types are different, converts the left side to a primitive value (by calling [].valueOf()) and ultimately ends up with 0. The right side (false) also gets converted to a zero, so they compare equal.

I don't completely agree that this example is a WTF (although unintuitive), because it's using the wrong operator. In JavaScript, you should always default to = or !, and think of and ! as special-purpose operators when you want to force values into a common type.

When is a String not a String?

This one does seem strange. The object wrappers for native types are definitely a mis-feature. Just remember that typeof is for native types (and functions), and instanceof is for object types (and that arrays are object types).

Array is false

These are also kind of weird. The solution is to always use = and ! for equality comparisons. There's almost never a need to compare values to true or false anyway, unless you only want those exact values. Just use x and !x.

null is not an Object

The first line, I can agree is somewhat of a WTF. The only justification for it is that null is an object in the same way that it is in Java or C#, i.e. assignable to object-typed variables. In JavaScript, where variables don't have types, that isn't necessary. I guess you could also argue that this is similar to typeof NaN === "number".

I don't even know what the WTF is supposed to be for the second line. Of course null !== Object. Object is a function that is the constructor for objects. The only thing it equals is itself, just like any other object or function.

parseInt WTF

parseInt (without a radix parameter) parses its first argument exactly the same way that JavaScript does. A leading "0x" implies hexadecimal; a leading "0" implies octal. If you don't want that, give it an explicit radix. To anyone who knows the language (or other C-like languages), it should make sense.

The reason parseInt("08") is 0, instead of NaN, is because parseInt parses everything it can until it reaches a character that's not valid in the (specified or implied) radix. You could definitely make a case for that part being a WTF.

Apparently, this does confuse a lot of people, because in ECMAScript 5, they removed the leading-zero-implies-octal feature. I don't have a strong opinion either way on that.

MIN_VALUE not so Min

This one is somewhat unfortunate, but a negative Number.MIN_VALUE would be redundant, because it would be the same as -Number.MAX_VALUE. The name comes from Java, which probably got it by modifying the name of the C macro (FLT|DBL|LDBL)_MIN.

NaN WTF 2

This is another one that seems to be illogical (remember, NaN is "Not a Number"), but it does make sense. The value of NaN is not a number, but its type is. In static languages like C, C++, Java, C#, etc. you can store NaN in variables with floating point number types. You have to be able to, because it's the result of invalid numerical operations.

Maybe a better way of looking at NaN is that it's an invalid number.

alert WTF

This is just another example of the limitations of floating point numbers. Any language without built-in large integers would do the same thing. Double-precision floating point numbers only guarantee about 15-16 digits of precision (more than you will ever need in most cases). If you need larger integers, use a BigInteger library (Here's another good one with an emphasis on public key cryptography). Unfortunately, I don't know of any good JavaScript libraries for more precise floating point numbers. If you know of any, let me know.

Declarations and Scope WTF

It's important to remember that variables in JavaScript are function-scoped, not block-scoped (the example doesn't use a block, but it wouldn't make a difference). Without understanding that, it would seem like var window never gets executed. Instead JavaScript "hoists" all variable declarations to the top of the function. Since variable declarations apply to the entire function, that makes sense.

To avoid confusion, don't refer to variables outside the block where you declare them, or simply declare all your variables at the top of the function.

fooNaN

[evaluated] as “foo” + (+ “bar”), which converts “bar” to not a number.
I'm not sure what to say about this one, except that it makes sense to me. The unary plus operator converts it's operand to a number, and "bar" is definitely not a number.

NaN WTF

I would argue that this does make sense, and no, I don't sniff glue.

This is another one that's defined by IEEE 754, and they got it right in my opinion. Remember that NaN is not a number. It's what you get when you try to do a calculation that is not valid, such as sqrt(-1) (in real numbers), 0/0, Math.acos(Math.PI), etc.

If NaN === NaN, that would be the same as saying sqrt(-1) === 0/0, which is obviously incorrect. An undefined number is not equal to anything, including another undefined number.

If you want to check a value for NaN, use the isNaN function.

window WTF

This one is kind of weird, but it makes sense. Any function that returns this (including [].reverse, or Array.prototype.reverse) will return the global object (window in a web browser) when they are called without a "this object".

You could argue that assigning the global object to this is a WTF, and I would probably agree with that.

Number WTF

The first line is incorrect. I'm assuming what they meant was isNaN('number') // true. If you changed the triple-equals comparison to the more-often used double-equals comparison, it would convert 'number' to NaN, but they still wouldn't be equal, because NaN != NaN (see above).

The first line used to be NaN === 'number' // true. The author has since corrected the mistake. See my response for a similar expression in "NaN WTF 2".

The second line is correct, but should really be a "wtfieee754". When you are dealing with numbers in JavaScript, it's important to realize that all numbers are IEEE 754 floating point numbers. The IEEE committee decided a long time ago that it was convenient to make division by zero equal to infinity. All languages that use IEEE 754 floating point have the same behavior here (technically, they could use the non-default trapping behavior, but I'm not aware of any languages that do that).

The third line is similar to the second one. Unfortunately, computers are not capable of representing all real numbers exactly, so we use floating point numbers. Since computers work best in binary, not all decimal numbers can be stored exactly, so 0.1 is really approximately 0.10000000000000001. It's never a good idea to use the equality operators to compare floating point numbers. Instead, use something like this: