Javascript Fun
1. Introduction
This document explores some of the more unusual idiosyncracies of the JavaScript language, some of which may trip you up if you're not aware of them.
2. Curious Expressions
Following is a list of expressions that are all true (i.e. the result of the expressions is always the boolean value true
). Some of the expressions are cute or ironic to look at. Others may just be plain puzzling to the uninitiated. Explanations appear below the expressions...
(7 / 100) * 100 != 7
Because of the way that JavaScript represents floating point numbers internally, the expression (7 / 100) * 100
actually produces the result 7.000000000000001
. It's not often that humans are better at computation than computers, but this would be one such occasion.
100000000000000000000 + 1 == 100000000000000000000 - 1
Another artifact of JavaScript's rather weak internal representation of numbers. 100000000000000000000
is represented internally as a floating point number that can be expressed in scientific notation as 1e+20
. Given the precision of JavaScript's floating point number representation, 1e+20 + 1
is equivalent to 1e+20 - 1
.
typeof null == 'object' && !(null instanceof Object)
This one is a bit hard to explain, especially in light of the fact that the statement typeof new String () == 'object' && new String () instanceof Object
is true.
typeof NaN == 'number'
Yeah, so in JavaScript NaN
is a special value for the number
type. So, the expression is technically correct, if appearing a little contradictory on the surface.
typeof !NaN == 'boolean'
For the purposes of boolean logic, notting NaN
produces the boolean value true
. This is not to say that NaN
is equivalent to the boolean value false
, though. One could make the argument that it would be more correct for coercing NaN
to a boolean type to produce the result NaB
(Not a Boolean), but JavaScript has no such concept of a boolean value that is in the paradoxical state of being neither true
nor false
, or both, or an indeterminate one.
NaN * 2 != 2 * NaN
Yeah, so this one just seems plain wrong on the surface. Why would swapping the two operands make a difference? Swapping operands in a multiplication, we have been taught, does not affect the outcome. So, then, shouldn't the two sides be equal? The trick comes in the odd behavior in JavaScript that the value NaN
is not equal to itself. So, it turns out that both sides in the boolean expression do produce the same result: they both produce the result NaN
. But, because NaN != NaN
, so the two sides - while having the same value - are not equal.
(NaN != NaN) && !(NaN < NaN) && !(NaN > NaN)
Ok, so if NaN
is not equal to itself, then it must be either greater than itself, or less than itself, right? Ummmm, yeah. Well, not really. Even though NaN
is not equal to iself, it is also not less than or, conversely, (and by implication) greater than itself. This falls squarely into the category of strange but true
. Robert Ripley would be proud.
(NaN && !NaN) != (!NaN && NaN)
So, both NaN && !NaN
and !NaN && NaN
produce the result NaN
. Now, because NaN
is not equal to itself, the two seemingly equivalent boolean expressions turn out not to be equivalent - even though they produce the same result. This is kind of a "paraphrasing" of the NaN * 2 != 2 * NaN
case.
(1 != NaN) && (1 == !NaN)
Just because 1
is not equal to NaN
, it doesn't follow that 1
should equal !NaN
. It's just a luck that the subtle underlying logic resembles a simplistic logic in this case. 1
is not equal to NaN
because nothing is equal to NaN
, but the reason 1
is equal to !NaN
is because notting NaN
produces the boolean value true
, and 1
is equivalent to true
in a non-strict equality operation.
isNaN (true) == false
Yeah, so you may have been lulled into thinking that a boolean is not a number. Seems perfectly reasonable, eh? Well, not so fast! The isNaN
function coerces its single argument to a number type by invoking the argument value's valueOf
instrinsic method. Now, for boolean type values, the built-in valueOf
converts the boolean value false
to 0
and the value true
to 1
. At this point, the isNaN
function is dealing with a value that has been resolved to a number, so it returns false
. Not exactly what you might expect (kind of like life).
isNaN (new Boolean) != (typeof new Boolean != 'number')
This is kind of a restatement of the previous example. While isNaN (new Boolean)
produces the result false
, typeof new Boolean != 'number'
produces the result true
.
isNaN (NaN) == !isNaN (!NaN)
So, NaN
is definitely not a number, so isNaN (NaN)
produces the result true
. Now, as shown earlier, !NaN
produces the result true
. So, isNaN (!NaN)
produces the result false
because - as also shown earlier - the isNaN
function coerces a boolean argument to a number and, therefore, returns false
. Now, notting that produces true
. So, the two sides of the equality operation are true
and equal. But it's not because the "inner" and "outer" nots in the right hand expression "cancel" each other out, or anything quite that simplistic.
isNaN (true) == isNaN (false)
The isNaN
function always returns false
when receiving a boolean argument, so the both sides of the equality operation are false
and, therefore, equal.
isNaN (5) == isNaN (isNaN (5))
On the left side of the equality, the number 5
is being tested for not a number, which unsurprisingly produces the result false
. On the right side, there is an extra layer of isNaN
. The inner test produces the value false
, like the left side. The outer test also produces the value false
, because the isNaN
function returns false
if it is supplied with a boolean argument. So, adding the extra layer of isNaN
keeps the value false
and both sides of the equality are equivalent.
isNaN (new Number) == isNaN (isNaN (isNaN (isNaN (isNaN (isNaN (isNaN (new Number)))))))
You can extrapolate from the previous example, of course. It really doesn't matter how many layers of isNaN
you add to the right side. Value's still gonna stay false
.
isNaN (NaN) != isNaN (isNaN (NaN))
Unlike the previous two examples, the same cannot be said for testing NaN
for not a number. In this case, the left side produces true
, but on the right side the inner test produces true
while the outer test then produces false
.
isNaN ('5') == false
Hmmmmmmmmmm....... just like you might have thought that a boolean was not a number, you might also have thought that a string is not a number. Once again, because the isNaN
function invokes the valueOf
instrinsic method on its argument to coerce a number, the string '5'
is successfully coerced to the number 5
, and so isNaN ('5')
returns false
.
isNaN ('five') == true
Not all strings are created equal. You may have been taught that five is a number, but JavaScript doesn't think so. Apparently, nobody taught JavaScript to read English. Coercing the string value 'five'
to a number produces the value NaN
, which - while not equal to itself - at least tests true for not being a number.
isNaN (!'a number') == false
Ok, so this one is just trying to be too cute for its own good. It says quite emphatically !'a number'
, so shouldn't JavaScript pay attention and oblige by testing true for not a number? Well, that's about as ridiculous as expecting that the expression isNaN ('I am a number, damn you')
should produce the result false
. As it turns out, notting any non-empty string produces the boolean value false
, because a non-empty string is considered equivalent to true
. Now, as shown earlier, the isNaN
function tests false for any boolean argument, because the boolean argument is successfully coerced to 0
or 1
.
isNaN (!!'a number') == false
Yeah, so don't think that adding another not before the !'a number'
will change the outcome. You're still supplying a boolean argument to the isNaN
function. You could also express this as isNaN (!'a number') == isNaN (!!'a number')
.
(null + null == 0) && (0 + 0 == 0) && (null + null != null)
So, if null + null
is equal to 0
, then null
seems like it's being treated as 0
. So, why isn't null + null
equal to null
? After all, we know that 0 + 0
is equal to 0
. What's going on? Simple. The value null
is coerced to the number value 0
when used in a numerical operation (such as summing), but it is not coerced when involved in an equality test. The value 0
is not considered equivalent to null
.
(0 != null) && (!0 == !null)
As shown earlier, the value 0
is not considered equivalent to the value null
in equality tests. However, notting both 0
and null
produces the result true
. So, while 0
is not equivalent to null
, !0
is equivalent to !null
.
(+null == +false) && (null != false)
Similar to the previous example, both null
and false
resolve to 0
when coerced to a number, but are not considered equivalent when compared to each other in an equality type operation.
true == false + 1
Adding 1
to false
makes it true
? Well, actually, adding 1
to false
first coerces false
to the number 0
and then produces the result 1
upon adding 1
. Now, 1
is considered equivalent to true
when involved in an equality operation.
(typeof true == 'boolean') && (!typeof true == false)
Well, it's obvious that the type of the value true
is 'boolean'
. Now, 'boolean'
is a string value, and notting any non-empty string produces the result false
, so !typeof true
gives you false
.
typeof new Boolean == 'object'
This just doesn't seem to make sense, unless you understand what's going on. You might be tempted to think that typeof new Boolean
should give you 'boolean'
. As it turns out, the type of value that is created using JavaScript's Boolean
core object is not the same as the type of a variable assigned with a simple boolean value. When using the Boolean
core object to construct an object, you get just that: an object, and not a primitive boolean value.
typeof !new Boolean == 'boolean'
To add irony to the mix, if you not an instance of the Boolean
core object and then get the type of that result, you then get 'boolean'
. On the surface, it may be strange to look at. Basically, notting any object in JavaScript produces the result false
, which is a boolean type value, so typeof !new Boolean
is 'boolean'
.
typeof typeof undefined == 'string'
So, the inner typeof
operation produces a result that is a string, even if its value is 'undefined'
. Therefore, the outer typeof
operation produces the result 'string'
.
typeof window.defined == 'undefined'
So, this is not guaranteed to always be the case, but it's a good bet that the window
object doesn't have a property defined called defined
. So, it looks like a contradiction, but it's about as weak an apparent contradiction as saying var number = 'string'
.
typeof (window.undefined = 'defined') == 'string'
If you want to just get mad with trying to confuse the issue. Nuff said.
(typeof function () {} == 'function') && (typeof function () {} () == 'undefined')
So, naturally the type of an empty anonymous function is 'function'
. But, if you add parentheses right after the empty function declaration, then you are essentially calling the function immediately after declaring it. Because the function is empty, it returns the result undefined
, the type of which is the string 'undefined'
.
(Infinity * 0 != 0) && (Infinity * 0 != Infinity) && (Infinity * 0 != NaN)
So, what exactly do you get when you multiply infinity by zero. You may initially think you should get zero. Not so. Do you get infinity? No. Do you get NaN
? No? Then what?!?!? Infinity multiplied by zero is not equal to anything then? Kind of. So, actually, you do get NaN
. And, as shown earlier, NaN
is not equal to itself, so Infinity * 0 != NaN
is true.
!new Boolean (false) == false
Seems like when you not false
you should get true
. Problem is, in this case you're not notting the primitive value false
but an instance of JavaScript's Boolean
core object instantiated with the value false
. Notting any object in JavaScript produces the boolean value false
. This behavior would appear to make the Boolean
core object less compelling, since an instance of this object is not interchangeable with a variable set to a primitive boolean value.
3. UIZE Trivia
"uize" is the traditional Scottish spelling of the word "use". | |
"UIZE" is the call sign of the Russian Federation ship BESSTRASHNYY, a rescue and salvage vessel built around 1963. | |
Ironically, the bit.ly short URL http://bit.ly/UiZe links to an article about interceptors in Flex. |