Ten Oddities And Secrets About JavaScript
JavaScript. At once bizarre and yet beautiful, it is surely the programming language that Pablo Picasso would have invented. Null is apparently an object, an empty array is apparently equal to false, and functions are bandied around as though they were tennis balls.
This article is aimed at intermediate developers who are curious about more advanced JavaScript. It is a collection of JavaScript’s oddities and well-kept secrets. Some sections will hopefully give you insight into how these curiosities can be useful to your code, while other sections are pure WTF material. So, let’s get started.
Data Types And Definitions
1. Null is an Object
Let’s start with everyone’s favorite JavaScript oddity, as well known as it is. Null is apparently an object, which, as far as contradictions go, is right up there with the best of them. Null? An object? “Surely, the definition of null is the total absence of meaningful value,” you say. You’d be right. But that’s the way it is. Here’s the proof:
alert(typeof null); //alerts 'object'
Despite this, null is not considered an instance of an object. (In case you didn’t know, values in JavaScript are instances of base objects. So, every number is an instance of the Number object, every object is an instance of the Object object, and so on.) This brings us back to sanity, because if null is the absence of value, then it obviously can’t be an instance of anything. Hence, the following evaluates to false:
alert(null instanceof Object); //evaluates false
2. NaN is a Number
You thought null being an object was ridiculous? Try dealing with the idea of NaN — “not a number” — being a number! Moreover, NaN is not considered equal to itself! Does your head hurt yet?
alert(typeof NaN); //alerts 'Number'
alert(NaN === NaN); //evaluates false
In fact NaN is not equal to anything. The only way to confirm that something is NaN is via the function isNaN().
3. An Array With No Keys == False (About Truthy and Falsy)
Here’s another much-loved JavaScript oddity:
alert(new Array() == false); //evaluates true
To understand what’s happening here, you need to understand the concepts of truthy and falsy. These are sort of true/false-lite, which will anger you somewhat if you majored in logic or philosophy.
I’ve read many explanations of what truthy and falsy are, and I feel the easiest one to understand is this: in JavaScript, every non-boolean value has a built-in boolean flag that is called on when the value is asked to behave like a boolean; like, for example, when you compare it to a boolean.
Because apples cannot be compared to pears, when JavaScript is asked to compare values of differing data types, it first “coerces” them into a common data type. False, zero, null, undefined, empty strings and NaN all end up becoming false — not permanently, just for the given expression. An example to the rescue:
var someVar = 0;
alert(someVar == false); //evaluates true
Here, we’re attempting to compare the number 0 to the boolean false. Because these data types are incompatible, JavaScript secretly coerces our variable into its truthy or falsy equivalent, which in the case of 0 (as I said above) is falsy.
You may have noticed that I didn’t include empty arrays in the list of falsies above. Empty arrays are curious things: they actually evaluate to truthy but, when compared against a boolean, behave like a falsy. Confused yet? With good cause. Another example perhaps?
var someVar = []; //empty array
alert(someVar == false); //evaluates true
if (someVar) alert('hello'); //alert runs, so someVar evaluates to true
To avoid coercion, you can use the value and type comparison operator, ===, (as opposed to ==, which compares only by value). So:
var someVar = 0;
alert(someVar == false); //evaluates true – zero is a falsy
alert(someVar === false); //evaluates false – zero is a number, not a boolean
Phew. As you’ve probably gathered, this is a broad topic, and I recommend reading up more on it — particularly on data coercion, which, while not uniquely a JavaScript concept, is nonetheless prominent in JavaScript.
I discuss the concept of truthy and falsy and data coercion more over here. And if you really want to sink your teeth into what happens internally when JavaScript is asked to compare two values, then check out section 11.9.3 of the ECMA-262 document specification.
Regular Expressions
4. replace() Can Accept a Callback Function
This is one of JavaScript’s best-kept secrets and arrived in v1.3. Most usages of replace() look something like this:
alert('10 13 21 48 52'.replace(/d+/g, '*')); //replace all numbers with *
This is a simple replacement: a string, an asterisk. But what if we wanted more control over how and when our replacements take place? What if we wanted to replace only numbers under 30? This can’t be achieved with regular expressions alone (they’re all about strings, after all, not maths). We need to jump into a callback function to evaluate each match.
alert('10 13 21 48 52'.replace(/d+/g, function(match) {
return parseInt(match) < 30 ? '*' : match;
}));
For every match made, JavaScript calls our function, passing the match into our match argument. Then, we return either the asterisk (if the number matched is under 30) or the match itself (i.e. no match should take place).
5. Regular Expressions: More Than Just Match and Replace
Many intermediate JavaScript developers get by just on match and replace with regular expressions. But JavaScript defines more methods than these two.
Of particular interest is test(), which works like match except that it doesn’t return matches: it simply confirms whether a pattern matches. In this sense, it is computationally lighter.
alert(/w{3,}/.test('Hello')); //alerts 'true'
The above looks for a pattern of three or more alphanumeric characters, and because the string Hello meets that requirement, we get true. We don’t get the actual match, just the result.
Also of note is the RegExp object, by which you can create dynamic regular expressions, as opposed to static ones. The majority of regular expressions are declared using short form (i.e. enclosed in forward slashes, as we did above). That way, though, you can’t reference variables, so making dynamic patterns is impossible. With RegExp(), though, you can.
function findWord(word, string) {
var instancesOfWord = string.match(new RegExp('\b'+word+'\b', 'ig'));
alert(instancesOfWord);
}
findWord('car', 'Carl went to buy a car but had forgotten his credit card.');
Here, we’re making a dynamic pattern based on the value of the argument word. The function returns the number of times that word appears in string as a word in its own right (i.e. not as a part of other words). So, our example returns car once, ignoring the car tokens in the words Carl and card. It forces this by checking for a word boundary (b) on either side of the word that we’re looking for.
Because RegExp are specified as strings, not via forward-slash syntax, we can use variables in building the pattern. This also means, however, that we must double-escape any special characters, as we did with our word boundary character.
Functions And Scope
6. You Can Fake Scope
The scope in which something executes defines what variables are accessible. Free-standing JavaScript (i.e. JavaScript that does not run inside a function) operates within the global scope of the window object, to which everything has access; whereas local variables declared inside functions are accessible only within that function, not outside.
var animal = 'dog';
function getAnimal(adjective) { alert(adjective+' '+this.animal); }
getAnimal('lovely'); //alerts 'lovely dog';
Here, our variable and function are both declared in the global scope (i.e. on window). Because this always points to the current scope, in this example it points to window. Therefore, the function looks for window.animal, which it finds. So far, so normal. But we can actually con our function into thinking that it’s running in a different scope, regardless of its own natural scope. We do this by calling its built-in call() method, rather than the function itself:
var animal = 'dog';
function getAnimal(adjective) { alert(adjective+' '+this.animal); };
var myObj = {animal: 'camel'};
getAnimal.call(myObj, 'lovely'); //alerts 'lovely camel'
Here, our function runs not on window but on myObj — specified as the first argument of the call method. Essentially, call() pretends that our function is a method of myObj (if this doesn’t make sense, you might want to read up on JavaScript’s system of prototypal inheritance). Note also that any arguments we pass to call() after the first will be passed on to our function — hence we’re passing in lovely as our adjective argument.
I’ve heard JavaScript developers say that they’ve gone years without ever needing to use this, not least because good code design ensures that you don’t need this smoke and mirrors. Nonetheless, it’s certainly an interesting one.
As an aside, apply() does the same job as call(), except that arguments to the function are specified as an array, rather than as individual arguments. So, the above example using apply() would look like this:
getAnimal.apply(myObj, ['lovely']); //func args sent as array
7. Functions Can Execute Themselves
There’s no denying it:
(function() { alert('hello'); })(); //alerts 'hello'
The syntax is simple enough: we declare a function and immediately call it just as we call other functions, with () syntax. You might wonder why we would do this. It seems like a contradiction in terms: a function normally contains code that we want to execute later, not now, otherwise we wouldn’t have put the code in a function.
One good use of self-executing functions (SEFs) is to bind the current values of variables for use inside delayed code, such as callbacks to events, timeouts and intervals. Here is the problem:
var someVar = 'hello';
setTimeout(function() { alert(someVar); }, 1000);
var someVar = 'goodbye';
Newbies in forums invariably ask why the alert in the timeout says goodbye and not hello. The answer is that the timeout callback function is precisely that — a callback — so it doesn’t evaluate the value of someVar until it runs. And by then, someVar has long since been overwritten by goodbye.
SEFs provide a solution to this problem. Instead of specifying the timeout callback implicitly as we do above, we return it from an SEF, into which we pass the current value of someVar as arguments. Effectively, this means we pass in and isolate the current value of someVar, protecting it from whatever happens to the actual variable someVar thereafter. This is like taking a photo of a car before you respray it; the photo will not update with the resprayed color; it will forever show the color of the car at the time the photo was taken.
var someVar = 'hello';
setTimeout((function(someVar) {
return function() { alert(someVar); }
})(someVar), 1000);
var someVar = 'goodbye';
This time, it alerts hello, as desired, because it is alerting the isolated version of someVar (i.e. the function argument, not the outer variable).
The Browser
8. Firefox Reads and Returns Colors in RGB, Not Hex
I’ve never really understood why Mozilla does this. Surely it realizes that anyone interrogating computed colors via JavaScript is interested in hex format and not RGB. To clarify, here’s an example:
Hello, world!
<script>
var ie = navigator.appVersion.indexOf('MSIE') != -1;
var p = document.getElementById('somePara');
alert(ie ? p.currentStyle.color : getComputedStyle(p, null).color);
</script>
While most browsers will alert ff9900, Firefox returns rgb(255, 153, 0), the RGB equivalent. Plenty of JavaScript functions are out there for converting RGB to hex.
Note that when I say computed color, I’m referring to the current color, regardless of how it is applied to the element. Compare this to style, which reads only style properties that were implicitly set in an element’s style attribute. Also, as you’ll have noticed in the example above, IE has a different method of detecting computed styles from other browsers.
As an aside, jQuery’s css() method encompasses this sort of computed detection, and it returns styles however they were applied to an element: implicitly or through inheritance or whatever. Therefore, you would relatively rarely need the native getComputedStyle and currentStyle.
Miscellaneous
9. 0.1 + 0.2 !== 0.3
This one is an oddity not just in JavaScript; it’s actually a prevailing problem in computer science, and it affects many languages. The output of this is 0.30000000000000004.
This has to do with an issue called machine precision. When JavaScript tries to execute the line above, it converts the values to their binary equivalents.
This is where the problem starts. 0.1 is not really 0.1 but rather its binary equivalent, which is a near-ish (but not identical) value. In essence, as soon as you write the values, they are doomed to lose their precision. You might have just wanted two simple decimals, but what you get, as Chris Pine notes, is binary floating-point arithmetic. Sort of like wanting your text translated into Russian but getting Belorussian. Similar, but not the same.
More is going on here, but it’s beyond the scope of this article (not to mention the mathematical capabilities of this author).
Workarounds for this problem are a favorite on computer science and developer forums. Your choice, to a point, comes down to the sort of calculations you’re doing. The pros and cons of each are beyond the scope of this article, but the common choice is between the following:
- Converting to integers and calculating on those instead, then converting back to decimals afterward; or
- Tweaking your logic to allow for a range rather than a specific result.
So, for example, rather than…
var num1 = 0.1, num2 = 0.2, shouldEqual = 0.3;
alert(num1 + num2 == shouldEqual); //false
… we would do this:
alert(num1 + num2 > shouldEqual - 0.001 && num1 + num2 < shouldEqual + 0.001); //true
Translated, this says that because 0.1 + 0.2 is apparently not 0.3, check instead that it’s more or less 0.3 — specifically, within a range of 0.001 on either side of it. The obvious drawback is that, for very precise calculations, this will return inaccurate results.
10. Undefined Can Be Defined
OK, let’s end with a silly, rather inconsequential one. Strange as it might sound, undefined is not actually a reserved word in JavaScript, even though it has a special meaning and is the only way to determine whether a variable is undefined. So:
var someVar;
alert(someVar == undefined); //evaluates true
So far, so normal. But:
undefined = "I'm not undefined!";
var someVar;
alert(someVar == undefined); //evaluates false!
You can also check Mozilla’s list of all reserved words in JavaScript for future reference.
Further Resources
- JavaScript Oddities Explained. Comparing.
- JavaScript Gotchas
- Yet More on Gotchas
- replace() callback functions
(al) (il)


Avinash Mudunuri
May 30th, 2011 4:48 amInteresting and useful info
Thanks SM
Avinash Mudunuri
May 30th, 2011 4:48 amInteresting and useful info
Thanks SM
Pablinho
May 30th, 2011 4:56 amInsightful tips for us JS newbies !!
Pablinho
May 30th, 2011 4:56 amInsightful tips for us JS newbies !!
sushil bharwani
May 30th, 2011 4:59 amNice collection and well summarized however “Firefox Reads and Returns Colors in RGB, Not Hex” is more of a browser issue and then there are so many of them like interpretation of document.getElementById(“xx”); in ie with some element having name as “xx”.
sushil bharwani
May 30th, 2011 4:59 amNice collection and well summarized however “Firefox Reads and Returns Colors in RGB, Not Hex” is more of a browser issue and then there are so many of them like interpretation of document.getElementById(“xx”); in ie with some element having name as “xx”.
Adham Dannaway
May 30th, 2011 5:24 amCool, lot’s of nice little tips. (I didn’t know that you could fake scope) :-)
Adham Dannaway
May 30th, 2011 5:24 amCool, lot’s of nice little tips. (I didn’t know that you could fake scope) :-)
ximi
May 30th, 2011 5:45 amVery good read, even if most of the issues mentioned here won’t really change/help with day by day javascript tasks.
ximi
May 30th, 2011 5:45 amVery good read, even if most of the issues mentioned here won’t really change/help with day by day javascript tasks.
catearcher
May 30th, 2011 6:13 amWhile undefined can be defined in Chrome 11 and other browsers, it can NOT be defined in Firefox 4.
catearcher
May 30th, 2011 6:13 amWhile undefined can be defined in Chrome 11 and other browsers, it can NOT be defined in Firefox 4.
Tomek Paczkowski
May 30th, 2011 6:21 amI tried to correct #7, but my previous comment “was marked as spam”. I’ll just say, there’s an error in #7.
Ryan Sharp
June 3rd, 2011 8:58 amThe error being that your example is NOT a function “calling itself”, it’s a function expression that is being immediately invoked (see: Ben Alman’s blog post on Immediately Invoked Function Expressions).
Tomek Paczkowski
May 30th, 2011 6:21 amI tried to correct #7, but my previous comment “was marked as spam”. I’ll just say, there’s an error in #7.
Ryan Sharp
June 3rd, 2011 8:58 amThe error being that your example is NOT a function “calling itself”, it’s a function expression that is being immediately invoked (see: Ben Alman’s blog post on Immediately Invoked Function Expressions).
Bob
May 30th, 2011 6:36 amThat wasn’t the best choice for demonstrating self-executing functions, especially since setTimeout accepts additional arguments that are passed to the callback:
var thing = “a”;
setTimeout(function(thing){
alert(thing);
}, 1000, thing);
thing=”b”;
//alerts “a” instead of “b”
mmocny
May 30th, 2011 8:54 amBob, you are right, though I ran into an issue where this didnt work in IE (possibly IE6) and SEF was the solution.
Though, this particular blog example is actually incorrect.
The SEF should return a callable function, instead it calls alert. It also doing use the argument passed to the function at all.
It should read:
setTimeout( (function(t) { return function() { alert(t); }; })(thing), 1000);
Or something like that.
Bob
May 30th, 2011 6:36 amThat wasn’t the best choice for demonstrating self-executing functions, especially since setTimeout accepts additional arguments that are passed to the callback:
var thing = “a”;
setTimeout(function(thing){
alert(thing);
}, 1000, thing);
thing=”b”;
//alerts “a” instead of “b”
mmocny
May 30th, 2011 8:54 amBob, you are right, though I ran into an issue where this didnt work in IE (possibly IE6) and SEF was the solution.
Though, this particular blog example is actually incorrect.
The SEF should return a callable function, instead it calls alert. It also doing use the argument passed to the function at all.
It should read:
setTimeout( (function(t) { return function() { alert(t); }; })(thing), 1000);
Or something like that.
josi
May 30th, 2011 6:40 am#7 is wrong! Those function do not execute themself, they are immediately invoked after declaration!
http://benalman.com/news/2010/11/immediately-invoked-function-expression/
josi
May 30th, 2011 6:40 am#7 is wrong! Those function do not execute themself, they are immediately invoked after declaration!
http://benalman.com/news/2010/11/immediately-invoked-function-expression/
Florian Cargoët
May 30th, 2011 6:51 amBuilt-in isNaN() is not the only way to check if something is NaN. Since NaN is not equal to itself, you can use “myVar !== myVar”.
function isNaN(n){
return n !== n;
}
n!==n is actually faster on my machine if used directly (not wrapped in a function)
http://jsperf.com/isnan-vs-n-n
Florian Cargoët
May 30th, 2011 6:51 amBuilt-in isNaN() is not the only way to check if something is NaN. Since NaN is not equal to itself, you can use “myVar !== myVar”.
function isNaN(n){
return n !== n;
}
n!==n is actually faster on my machine if used directly (not wrapped in a function)
http://jsperf.com/isnan-vs-n-n
JM
May 30th, 2011 7:07 amNever use such an condition as in #8. Browser detection is bad; feature detection should be used instead.
window.getComputedStyle ? window.getComputedStyle(p, null).color : p.currentStyle.color;Andy Croxall
May 30th, 2011 8:59 amThis is a fair point, but since currentStyle is unique to IE, I felt it safe to detect IE in this case. But yes, it normally makes sense to detect functionality, not user agent.
JM
May 30th, 2011 7:07 amNever use such an condition as in #8. Browser detection is bad; feature detection should be used instead.
window.getComputedStyle ? window.getComputedStyle(p, null).color : p.currentStyle.color;Andy Croxall
May 30th, 2011 8:59 amThis is a fair point, but since currentStyle is unique to IE, I felt it safe to detect IE in this case. But yes, it normally makes sense to detect functionality, not user agent.
Gareth
May 30th, 2011 7:23 am10. Undefined can (usually) be defined
/* But */ typeof(anUndefinedVariable) == ‘undefined’; // always
Gareth
May 30th, 2011 7:23 am10. Undefined can (usually) be defined
/* But */ typeof(anUndefinedVariable) == ‘undefined’; // always
Jon
May 30th, 2011 7:24 amvalue == undefined is not the only way to determined defined-ness.
You can also do: typeof value === ‘undefined’. I almost always use this way instead.
Jon
May 30th, 2011 7:24 amvalue == undefined is not the only way to determined defined-ness.
You can also do: typeof value === ‘undefined’. I almost always use this way instead.
Wolfram Hempel
May 30th, 2011 8:28 amHow about that one?
parseInt(“07″) = 7;
parseInt(“08″) = 0;
Just try it…for some reason JavaScript uses the octal-system for those values, so what you need to do is add the numerative system to use as a second parameter
parseInt(“08”,10) = 8;
This might seem as a rare problem at first, but only until you try creating dates from strings…
Bertold von Dormilich
May 31st, 2011 8:23 amparseInt(): [ECMAScript 262, section 15.1.2.2]
When radix is 0 or undefined and the string’s number begins with a 0 digit not followed by an x or X, then the implementation may, at its discretion, interpret the number either as being octal or as being decimal.
Wolfram Hempel
May 30th, 2011 8:28 amHow about that one?
parseInt(“07″) = 7;
parseInt(“08″) = 0;
Just try it…for some reason JavaScript uses the octal-system for those values, so what you need to do is add the numerative system to use as a second parameter
parseInt(“08”,10) = 8;
This might seem as a rare problem at first, but only until you try creating dates from strings…
Bertold von Dormilich
May 31st, 2011 8:23 amparseInt(): [ECMAScript 262, section 15.1.2.2]
When radix is 0 or undefined and the string’s number begins with a 0 digit not followed by an x or X, then the implementation may, at its discretion, interpret the number either as being octal or as being decimal.
Keoki Zee
May 30th, 2011 8:47 amFor #3, truthiness/falsiness is not unique to JavaScript of course. PHP uses just about the same rules, and even the same operators (i.e. “==” vs “===”), while C++ has long evaluated 0 and null (in boolean contexts) as false as well.
Keoki Zee
May 30th, 2011 8:47 amFor #3, truthiness/falsiness is not unique to JavaScript of course. PHP uses just about the same rules, and even the same operators (i.e. “==” vs “===”), while C++ has long evaluated 0 and null (in boolean contexts) as false as well.
Sameh Khalil
May 30th, 2011 8:53 amReally good article, I know JavaScript have some oddities, but not that many.
Sameh Khalil
May 30th, 2011 8:53 amReally good article, I know JavaScript have some oddities, but not that many.
Keshav
May 30th, 2011 9:25 amReally Very Good Article.. :) getting dipper into javascript . Thanks for sharing..
Keshav
May 30th, 2011 9:25 amReally Very Good Article.. :) getting dipper into javascript . Thanks for sharing..
Alejandro
May 30th, 2011 10:16 amA couple of comments:
1. Null is an Object
Null is NOT an object, despite of what the typeof operator says. This is an error in the language.
2. NaN is a number
You might want to add that the proper way to test for NaN values is with the isNaN() function not with the equality operators.
3. An Array With No Keys == False (About Truthy and Falsy)
I think the title is misleading, anything that’s not a falsy value evaluates to true. Even if the array had members it would still evaluate to true.
9. 0.1 + 0.2 !== 0.3
You might want to add that the proper way to make this work is converting the decimals into integers, make whatever operations you need and convert back to decimals.
10. Undefined Can Be Defined
You might want to add that you can use void(0) to get undefined, even when it has been defined to something else.
Alejandro
May 30th, 2011 10:16 amA couple of comments:
1. Null is an Object
Null is NOT an object, despite of what the typeof operator says. This is an error in the language.
2. NaN is a number
You might want to add that the proper way to test for NaN values is with the isNaN() function not with the equality operators.
3. An Array With No Keys == False (About Truthy and Falsy)
I think the title is misleading, anything that’s not a falsy value evaluates to true. Even if the array had members it would still evaluate to true.
9. 0.1 + 0.2 !== 0.3
You might want to add that the proper way to make this work is converting the decimals into integers, make whatever operations you need and convert back to decimals.
10. Undefined Can Be Defined
You might want to add that you can use void(0) to get undefined, even when it has been defined to something else.
Patrick Corcoran
May 30th, 2011 10:42 amThere is nothing wrong with returning color values in RGB. Hex cannot express all the possible color values of a 32-bit color space. And while RGB cannot either, it is at least more easily extensible to become RGBA when necessary:
>>> document.body.style.backgroundColor = ‘#000′
>>> document.body.style.backgroundColor
“rgb(0, 0, 0)”
>>> document.body.style.backgroundColor = ‘rgba(0,0,0,0.5)’
>>> document.body.style.backgroundColor
“rgba(0, 0, 0, 0.5)”
…and by the way, this also isn’t a JavaScript language oddity, it’s a browser-specific DOM oddity.
Andy Croxall
May 30th, 2011 11:18 amYes, of course it’s a browser issue rather than a JS one, but since it affects only JS it’s relevant to this article.
Patrick Corcoran
May 30th, 2011 12:02 pmIt has nothing to do with JavaScript. This quirk would be exposed by any scripting language plugged into the browser.
Andy Croxall
May 30th, 2011 12:37 pm…of which one (and indeed the most common) is Javascript. So I don’t quite see how you can say this issue has nothing to do with Javascript. It’s an issue that will affect you if you wish to detect computer colour using JS, with regards to Mozilla browsers. What’s not to be agreed on there?
Mike Marynowski
May 31st, 2011 11:07 pmHex can, and has been, easily extended in ARGB format. #FF000000 is solid black in graphic editors and environments like Silverlight. Just as easy to return 8 digit hex for ARGB colors in javascript.
Patrick Corcoran
May 30th, 2011 10:42 amThere is nothing wrong with returning color values in RGB. Hex cannot express all the possible color values of a 32-bit color space. And while RGB cannot either, it is at least more easily extensible to become RGBA when necessary:
>>> document.body.style.backgroundColor = ‘#000′
>>> document.body.style.backgroundColor
“rgb(0, 0, 0)”
>>> document.body.style.backgroundColor = ‘rgba(0,0,0,0.5)’
>>> document.body.style.backgroundColor
“rgba(0, 0, 0, 0.5)”
…and by the way, this also isn’t a JavaScript language oddity, it’s a browser-specific DOM oddity.
Andy Croxall
May 30th, 2011 11:18 amYes, of course it’s a browser issue rather than a JS one, but since it affects only JS it’s relevant to this article.
Patrick Corcoran
May 30th, 2011 12:02 pmIt has nothing to do with JavaScript. This quirk would be exposed by any scripting language plugged into the browser.
Andy Croxall
May 30th, 2011 12:37 pm…of which one (and indeed the most common) is Javascript. So I don’t quite see how you can say this issue has nothing to do with Javascript. It’s an issue that will affect you if you wish to detect computer colour using JS, with regards to Mozilla browsers. What’s not to be agreed on there?
Mike Marynowski
May 31st, 2011 11:07 pmHex can, and has been, easily extended in ARGB format. #FF000000 is solid black in graphic editors and environments like Silverlight. Just as easy to return 8 digit hex for ARGB colors in javascript.
Mike McNally
May 30th, 2011 3:10 pmString constants, numeric constants, and boolean constants are **not** instances of “String” and “Number” and “Boolean”; they’re primitive values. In appropriate circumstances (or, if you’re from certain language backgrounds, you might say, “at the drop of a hat”), primitive values are promoted to their object-y cousin types, so in most ways they *behave* like instances. They truly are not, however.
drza
May 30th, 2011 5:59 pmregardless of the handful of debatable issues in this article, the one i wanted to jump in on was your useless, ignorant, phishing for attention comment. fine i bit.
try this cool guy “JavaScript is the language of
wannabe‘front end’ developers” – you tool.fyi, i’m pretty certain that quite a few front-end developers regularly benefit from the articles contributed on this site (the granddaddy of resources/articles regarding this front-end design and engineering industry specifically).
oh, and being an unwarranted article hater is the language of you being a herb. there’s a way to contribute to a discussion without coming across as a sh!t-talking d-bag.
be right, wrong, nice or quiet. thanks for playing.
Andy Croxall
May 31st, 2011 1:46 amTotally agree, drza. I learned long ago that programmers include many who are very sarcastic, spiteful and otherwise full of anger. It’s sad, really, to be so negative.
Daniel Pataki
June 1st, 2011 12:53 amEvery group includes these people :) Also, sarcasm is awesome, spite and anger are the bad qualities :)
whatgoodisaroad
May 30th, 2011 8:46 pmIt’s not the slightest bit odd that null is an object or that NaN is a number.
In most OOP languages (like Java or C#) Null can only be applied to types that inherit Object because they’re reference types. This is clearest in C++ because null is defined as a constant reference to the zero-pointer. It makes no sense for null to be a value type.
NaN is defined in other languages too. In for example, it’s defined on Ints and Floats. The only difference here is that JavaScript’s numbers are stored in a type *called* “Number”. What else should NaN be defined on? There’s nothing else that makes sense.
Additionally, the concept of truthiness and falsiness aren’t that unusual; they’re part of every ECMA variant and are a takeaway from the way a lot of things work in C.
The real deep and dark oddities in JavaScript all involve the Date object.
vlad
June 2nd, 2011 3:59 amDamned right, I always forget that January actually 0…
whatgoodisaroad
May 30th, 2011 8:46 pmIt’s not the slightest bit odd that null is an object or that NaN is a number.
In most OOP languages (like Java or C#) Null can only be applied to types that inherit Object because they’re reference types. This is clearest in C++ because null is defined as a constant reference to the zero-pointer. It makes no sense for null to be a value type.
NaN is defined in other languages too. In for example, it’s defined on Ints and Floats. The only difference here is that JavaScript’s numbers are stored in a type *called* “Number”. What else should NaN be defined on? There’s nothing else that makes sense.
Additionally, the concept of truthiness and falsiness aren’t that unusual; they’re part of every ECMA variant and are a takeaway from the way a lot of things work in C.
The real deep and dark oddities in JavaScript all involve the Date object.
vlad
June 2nd, 2011 3:59 amDamned right, I always forget that January actually 0…
Ashish
May 30th, 2011 10:12 pmWow, gr8 JS tips.
very much useful. Thanks!
Ashish
May 30th, 2011 10:12 pmWow, gr8 JS tips.
very much useful. Thanks!
jiazheng
May 30th, 2011 10:34 pmAn array with only one key which value is 0 also equals FALSE. That is:
[0] == false; // true
Andy Croxall
May 30th, 2011 11:46 pmYeap, this is also a falsy. Thanks for sharing.
Axel Rauschmayer
May 31st, 2011 1:22 pm[0] == false; // true
This is not due to [0] being falsy (arrays never are), but because of how == works: If any value is compared to a boolean via ==, the boolean is converted to a number and then compared. Behold:
> [0] == false
true
> [0] ? true : false
true
> [0] == 0
true
> 0 == false
true
jiazheng
May 30th, 2011 10:34 pmAn array with only one key which value is 0 also equals FALSE. That is:
[0] == false; // true
Andy Croxall
May 30th, 2011 11:46 pmYeap, this is also a falsy. Thanks for sharing.
Axel Rauschmayer
May 31st, 2011 1:22 pm[0] == false; // true
This is not due to [0] being falsy (arrays never are), but because of how == works: If any value is compared to a boolean via ==, the boolean is converted to a number and then compared. Behold:
> [0] == false
true
> [0] ? true : false
true
> [0] == 0
true
> 0 == false
true
Andy Croxall
June 7th, 2011 12:52 amYes – this is JS data coercion in action. Thanks for sharing.
Osvaldas
May 30th, 2011 11:11 pmYou should have skipped the last code example..
Osvaldas
May 30th, 2011 11:11 pmYou should have skipped the last code example..
Andy Croxall
May 30th, 2011 11:47 pmThe code in part 7 (SEFs) contained an error that has been pointed out to me in comments. I have corrected the code and removed the comments, since the error they refer to is no longer present. Thanks for the feedback.
Christophe
May 31st, 2011 2:01 amMy two cents: removing regular comments is a bad practice and won’t encourage these commenters to help you next time. Why not just say thanks?
Andy Croxall
May 31st, 2011 3:49 amPerhaps you’re right, Christophe; I just felt that, if I left them, the comments would be referencing code that wasn’t there anymore, which would therefore be confusing to new readers. By mentioning my error and deletion of comments in a new comment, I hope it was clear I wasn’t trying to avoid criticism!
Michael
May 31st, 2011 5:59 amPerhaps just adding a note in to the article mentioning that the code has been fixed and thanks to the comments would have been more appropriate.
Andy Croxall
May 30th, 2011 11:47 pmThe code in part 7 (SEFs) contained an error that has been pointed out to me in comments. I have corrected the code and removed the comments, since the error they refer to is no longer present. Thanks for the feedback.
Christophe
May 31st, 2011 2:01 amMy two cents: removing regular comments is a bad practice and won’t encourage these commenters to help you next time. Why not just say thanks?
Andy Croxall
May 31st, 2011 3:49 amPerhaps you’re right, Christophe; I just felt that, if I left them, the comments would be referencing code that wasn’t there anymore, which would therefore be confusing to new readers. By mentioning my error and deletion of comments in a new comment, I hope it was clear I wasn’t trying to avoid criticism!
Michael
May 31st, 2011 5:59 amPerhaps just adding a note in to the article mentioning that the code has been fixed and thanks to the comments would have been more appropriate.
Christophe
May 31st, 2011 2:04 amThanks, nice to have all those oddities referenced in one single article. Useful stuff in the comments too, some of it would deserve to be added to the post.
Christophe
May 31st, 2011 2:04 amThanks, nice to have all those oddities referenced in one single article. Useful stuff in the comments too, some of it would deserve to be added to the post.
scottgroovez
May 31st, 2011 2:31 am#9 has caught me out in the past (in AS though). Solved by converting to integers as pointed out in the article. Nice to know the reasons though.
scottgroovez
May 31st, 2011 2:31 am#9 has caught me out in the past (in AS though). Solved by converting to integers as pointed out in the article. Nice to know the reasons though.
Balázs Galambosi
May 31st, 2011 3:25 am[1] 4.3.12: Null type – type whose sole value is the null value.
[2] 11.4.3: The typeof Operator
Typeof doesn’t really check the type of null but returns a string value according to a table:
It is an error in the language.
http://es5.github.com/#x4.3.11
http://es5.github.com/#x11.4.3
Balázs Galambosi
May 31st, 2011 3:25 am[1] 4.3.12: Null type – type whose sole value is the null value.
[2] 11.4.3: The typeof Operator
Typeof doesn’t really check the type of null but returns a string value according to a table:
It is an error in the language.
http://es5.github.com/#x4.3.11
http://es5.github.com/#x11.4.3
David Colblin
May 31st, 2011 3:47 amNow i know JS oddities exist, i will verify these before tearing my hair ;)
David Colblin
May 31st, 2011 3:47 amNow i know JS oddities exist, i will verify these before tearing my hair ;)
Vassilis
May 31st, 2011 4:10 amMy personal favorite:
var foo = [0];
console.log(foo == !foo); // true
console.log(foo == foo); // true
Axel Rauschmayer
May 31st, 2011 1:40 pmAny reason to have a single array element? Just curious… Your example works as “well” with [].
It just goes to show that one should never use == and its weird conversion rules: JavaScript evaluates the first expression’s right hand side !foo to false and converts that to 0. That 0 is then compared to the result of converting foo to a number (which is also 0). The second expression is true because objects are always equal to themselves.
Vassilis
May 31st, 2011 4:10 amMy personal favorite:
var foo = [0];
console.log(foo == !foo); // true
console.log(foo == foo); // true
Axel Rauschmayer
May 31st, 2011 1:40 pmAny reason to have a single array element? Just curious… Your example works as “well” with [].
It just goes to show that one should never use == and its weird conversion rules: JavaScript evaluates the first expression’s right hand side !foo to false and converts that to 0. That 0 is then compared to the result of converting foo to a number (which is also 0). The second expression is true because objects are always equal to themselves.
Michael Ward
May 31st, 2011 4:54 amOne of the best articles I have read on SM – insightful, useful and quick to the point.
Also, ignore the pedants. They can while their lives away arguing that the javascript attitude to NULL is going to cause the universe to implode, whereas back in reality we can concern ourselves with matters that are more practical than academic.
And guys, correctness does matter – but it has its time and place, and we don’t need to be 100% correct to get a message across – often such a level of correctness simply clouds the issue at hand.
Michael Ward
May 31st, 2011 4:54 amOne of the best articles I have read on SM – insightful, useful and quick to the point.
Also, ignore the pedants. They can while their lives away arguing that the javascript attitude to NULL is going to cause the universe to implode, whereas back in reality we can concern ourselves with matters that are more practical than academic.
And guys, correctness does matter – but it has its time and place, and we don’t need to be 100% correct to get a message across – often such a level of correctness simply clouds the issue at hand.
Ryan Cannon
May 31st, 2011 11:01 amIf you liked this article, I recommend http://wtfjs.com/ which is a blog dedicated to weird idiosyncrasies of JavaScript.
Ryan Cannon
May 31st, 2011 11:01 amIf you liked this article, I recommend http://wtfjs.com/ which is a blog dedicated to weird idiosyncrasies of JavaScript.
Sam Deering
May 31st, 2011 4:17 pmAwesome post, love the NaN == NaN example!
Sam Deering
May 31st, 2011 4:17 pmAwesome post, love the NaN == NaN example!
Christian Sciberras
June 1st, 2011 12:51 amVery interesting article, though, sadly, nothing new. Hope to see more “secret” quirks in the future.
Christian Sciberras
June 1st, 2011 12:51 amVery interesting article, though, sadly, nothing new. Hope to see more “secret” quirks in the future.
Kamran
June 1st, 2011 3:05 amNice stuff! :)
Kamran
June 1st, 2011 3:05 amNice stuff! :)
Sean
June 1st, 2011 5:02 amGreat article, thanks for the helpful tips and it’s wonderfully written.
Sean
June 1st, 2011 5:02 amGreat article, thanks for the helpful tips and it’s wonderfully written.
Kalpesh
June 1st, 2011 6:55 amVery well written and nicely presented.
Kalpesh
June 1st, 2011 6:55 amVery well written and nicely presented.
Oz
June 1st, 2011 1:55 pmDurex, really? :D
Oz
June 1st, 2011 1:55 pmDurex, really? :D
Kasia
June 1st, 2011 2:09 pmOh, I love this language and it’s quirks :)
I’m not really sure about that part from 1st paragraph:
“(…) every number is an instance of the Number object, every object is an instance of the Object object, and so on.”
It’s true only if you use Number constructor NOT literals (same for strings and booleans)
so:
var a = 1;
a instanceof Number // false
a instanceof Object // false
typeof a // number
but:
var b = new Number(1);
b instanceof Number // true
b instanceof Object // true
typeof b // object
With objects and arrays it works both ways:
var a = [];
typeof a // object (!)
a instanceof Array // true
a instanceof Object // true
and:
var b = new Array();
typeof b // object
b instanceof Array // true
b instanceof Object // true
I say – don’t use constructors – use literals :)
And additional quirk about arrays and double equals:
[ ] and ![ ] evaluates to false, soooo:
[] == ![] // true (!!!)
Bazinga! Moral? Always use === :)
Kasia
June 1st, 2011 2:09 pmOh, I love this language and it’s quirks :)
I’m not really sure about that part from 1st paragraph:
“(…) every number is an instance of the Number object, every object is an instance of the Object object, and so on.”
It’s true only if you use Number constructor NOT literals (same for strings and booleans)
so:
var a = 1;
a instanceof Number // false
a instanceof Object // false
typeof a // number
but:
var b = new Number(1);
b instanceof Number // true
b instanceof Object // true
typeof b // object
With objects and arrays it works both ways:
var a = [];
typeof a // object (!)
a instanceof Array // true
a instanceof Object // true
and:
var b = new Array();
typeof b // object
b instanceof Array // true
b instanceof Object // true
I say – don’t use constructors – use literals :)
And additional quirk about arrays and double equals:
[ ] and ![ ] evaluates to false, soooo:
[] == ![] // true (!!!)
Bazinga! Moral? Always use === :)
Graham De Young
June 2nd, 2011 9:20 amThe best, cross-browser way to test if a variable (foo) is defined is:
if (typeof foo != ‘undefined’) {
// foo is defined
}
Graham De Young
June 2nd, 2011 9:20 amThe best, cross-browser way to test if a variable (foo) is defined is:
if (typeof foo != ‘undefined’) {
// foo is defined
}
Abhijit
June 4th, 2011 3:01 amI think you can also do
if (!!foo) {
// foo is defined
}
Graham De Young
June 2nd, 2011 9:26 am@Kasia,
Actually, literals are instances of objects. Numbers are more difficult to work with, but if you write something like (1).toFixed(2), it will return 1.00.
String literals can be manipulated directly. ‘This is a string’.charAt(0) returns ‘T’.
Jared
June 3rd, 2011 9:17 amNo, native literals are not object instances. They are coerced to objects when you invoke methods on them.
Graham De Young
June 2nd, 2011 9:26 am@Kasia,
Actually, literals are instances of objects. Numbers are more difficult to work with, but if you write something like (1).toFixed(2), it will return 1.00.
String literals can be manipulated directly. ‘This is a string’.charAt(0) returns ‘T’.
Jared
June 3rd, 2011 9:17 amNo, native literals are not object instances. They are coerced to objects when you invoke methods on them.
Gökhan Bora
June 3rd, 2011 12:57 amAll js programmers need to read. Thanks.
Gökhan Bora
June 3rd, 2011 12:57 amAll js programmers need to read. Thanks.
Jared
June 3rd, 2011 9:14 amYour explanation for #1 illustrates a poor understanding of the JavaScript type system. Once you read the language spec, the behavior is what you’d expect.
4.3.9 *undefined value*: primitive value used when a variable has not been assigned a value.
4.3.11 *null value*: primitive value that represents the intentional absence of any object value.
http://www.ecma-international.org/publications/standards/Ecma-262.htm
#2 illustrates a poor understanding of floating point arithmetic. Shame on you. The reason you have to use isNaN(x) is because there are multiple 32-bit sequences that don’t represent valid floating-point numbers, and all are considered “not numbers”.
http://en.wikipedia.org/wiki/NaN
#10 is wrong too. There are many other ways to tell if a value is undefined, which still work if you set undefined to something else:
(x === void 0)
(typeof x == “undefined”) // works even if x has not been declared
Jared
June 3rd, 2011 9:14 amYour explanation for #1 illustrates a poor understanding of the JavaScript type system. Once you read the language spec, the behavior is what you’d expect.
4.3.9 *undefined value*: primitive value used when a variable has not been assigned a value.
4.3.11 *null value*: primitive value that represents the intentional absence of any object value.
http://www.ecma-international.org/publications/standards/Ecma-262.htm
#2 illustrates a poor understanding of floating point arithmetic. Shame on you. The reason you have to use isNaN(x) is because there are multiple 32-bit sequences that don’t represent valid floating-point numbers, and all are considered “not numbers”.
http://en.wikipedia.org/wiki/NaN
#10 is wrong too. There are many other ways to tell if a value is undefined, which still work if you set undefined to something else:
(x === void 0)
(typeof x == “undefined”) // works even if x has not been declared
Jared
June 3rd, 2011 9:25 amThis article and the comments remind me how said it is that so many JS developers have no background in Computer Science. There’s no excuse these days. Looks at all of these freely available texts on programming language theory:
http://www.cs.uu.nl/wiki/Techno/ProgrammingLanguageTheoryTextsOnline
And when you want to learn a new language, read the language specification, not a lame tutorial with ads and a high page rank. For JavaScript:
http://www.ecma-international.org/publications/standards/Ecma-262.htm
Jared
June 3rd, 2011 9:25 amThis article and the comments remind me how said it is that so many JS developers have no background in Computer Science. There’s no excuse these days. Looks at all of these freely available texts on programming language theory:
http://www.cs.uu.nl/wiki/Techno/ProgrammingLanguageTheoryTextsOnline
And when you want to learn a new language, read the language specification, not a lame tutorial with ads and a high page rank. For JavaScript:
http://www.ecma-international.org/publications/standards/Ecma-262.htm
Steve M
June 5th, 2011 9:34 pmHi Andy,
Well, as much as you did my head in with all these downright weird things about JS – which I never knew… It was still facinating to see the quirks of this language.
Even though I may not have a need generally speaking to use many, if not any of the things mentioned, and whether they are 100% ‘technically’ correct or not – who cares. Your article prompts discussion and gives people the tools, basic information and resources to go and investigate things for themselves.
Nice work.
daniel
June 7th, 2011 11:09 pmvery good article. thanks for sharing
Adrian Grigore
June 8th, 2011 7:29 amGreat article! But may I suggest that you rename it to “further proof that Javascript is evil” ;-)
Christian
June 19th, 2011 10:02 amJust a quick note:
In both the examples for the String.replace method accepting callback functions (4. Regular Expressions) there’s a backslash missing in the RegEx pattern for selecting digits: /\d+/g
Other than that, good and informative article!
Jerrell B
July 3rd, 2011 7:29 pmalert(/w{3,}/.test(‘Hello’)); // I receive false not true
has this been addressed? I’m using FireBug in Firefox 5 for testing
DestinyXie
August 31st, 2011 12:49 am0.1 + 0.2 !== 0.3 有趣~
Irk
June 5th, 2012 10:23 amAll this time without knowing that is was possible to fake scope() :)
Patrick Weygand
November 25th, 2012 2:47 pmA bit more explanation on []
if ([]) {
console.log( [] == true); // => false
}
for the lazy: http://jsfiddle.net/Sxa2c/
Wait how did it get into the loop? http://james.padolsey.com/javascript/truthy-falsey/
Apparently an internal function toBoolean is called for an if statement which converts like so
http://bclary.com/2004/11/07/#a-9.2
all objects evaluate to true. But isn’t null an object? Yep but its got a special exception as seen in the table above.
But wait why then is [] == false, well because the == operator uses a different algorithm,
it uses toNumber (internal)
which in turn uses toPrimitive,
which in turn uses valueOf if the result is a primitive (which its not) and falls back to toString
which returns the primitive “”
which it applies toNumber again this time calling Number(“”)
which returns 0
which I am guessing it applies toBoolean against as the table cited below has no entry for number and boolean comparison. (and it should because the fall through false would not make sense for 1 == false)
which according to toBoolean’s spec 0 gives us false.
http://javascriptweblog.wordpress.com/2011/02/07/truth-equality-and-javascript/
drza
May 30th, 2011 5:59 pmregardless of the handful of debatable issues in this article, the one i wanted to jump in on was your useless, ignorant, phishing for attention comment. fine i bit.
try this cool guy “JavaScript is the language of
wannabe‘front end’ developers” – you tool.fyi, i’m pretty certain that quite a few front-end developers regularly benefit from the articles contributed on this site (the granddaddy of resources/articles regarding this front-end design and engineering industry specifically).
oh, and being an unwarranted article hater is the language of you being a herb. there’s a way to contribute to a discussion without coming across as a sh!t-talking d-bag.
be right, wrong, nice or quiet. thanks for playing.
Andy Croxall
May 31st, 2011 1:46 amTotally agree, drza. I learned long ago that programmers include many who are very sarcastic, spiteful and otherwise full of anger. It’s sad, really, to be so negative.
daniel
June 7th, 2011 11:13 pmwhat’s wrong with you man?
Daniel Pataki
June 1st, 2011 12:53 amEvery group includes these people :) Also, sarcasm is awesome, spite and anger are the bad qualities :)