DIR : /home/kozerus/public_html/pn/uize/site-source/appendixes/javascript-fun.simple
/home/kozerus/public_html/pn/uize/site-source/appendixes
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.
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.
UIZE Trivia
- "uize" is the traditional Scottish spelling of the word "use".
- "UIZE" is the call sign of the Russian Federation ship [[http://www.rs-head.spb.ru/en/regbook/file_shipa/63/630139_e.htm][BESSTRASHNYY]], a rescue and salvage vessel built around 1963.
- Ironically, the [[http://bit.ly][bit.ly]] short URL [[http://bit.ly/UiZe]] links to an article about interceptors in Flex.
//
koh5_pano
Drag mouse to navigate.
Navigation
- Left/Right Mouse drag: Changes camera heading.
- Up/Sown Mouse drag: Changes camera pitch.
- Scroll wheel: Changes camera field of view.
- I-Key: Displays Info panel with canvas size, image size and FPS.
17.Aug.2010, Martin Wengenmayer