Ten Oddities And Secrets About JavaScript

Advertisement

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:

  1. Converting to integers and calculating on those instead, then converting back to decimals afterward; or
  2. 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

(al) (il)

↑ Back to top

Andy Croxall is a Web developer from Wandsworth, London, England. He is a Javascript specialist and is an active member of the jQuery community, posting plugins and extensions. He has worked for clients ranging from the London Stock Exchange to Durex. You can keep up with him and his projects and creations on his website, mitya.co.uk.

  1. 1

    Avinash Mudunuri

    May 30, 2011 4:48 am

    Interesting and useful info
    Thanks SM

    1
  2. 2

    Avinash Mudunuri

    May 30, 2011 4:48 am

    Interesting and useful info
    Thanks SM

    0
  3. 3

    Insightful tips for us JS newbies !!

    0
  4. 4

    Insightful tips for us JS newbies !!

    0
  5. 5

    sushil bharwani

    May 30, 2011 4:59 am

    Nice 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”.

    2
  6. 6

    sushil bharwani

    May 30, 2011 4:59 am

    Nice 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”.

    0
  7. 7

    Adham Dannaway

    May 30, 2011 5:24 am

    Cool, lot’s of nice little tips. (I didn’t know that you could fake scope) :-)

    1
  8. 8

    Adham Dannaway

    May 30, 2011 5:24 am

    Cool, lot’s of nice little tips. (I didn’t know that you could fake scope) :-)

    -1
  9. 9

    Very good read, even if most of the issues mentioned here won’t really change/help with day by day javascript tasks.

    1
  10. 10

    Very good read, even if most of the issues mentioned here won’t really change/help with day by day javascript tasks.

    0
  11. 11

    While undefined can be defined in Chrome 11 and other browsers, it can NOT be defined in Firefox 4.

    0
  12. 12

    While undefined can be defined in Chrome 11 and other browsers, it can NOT be defined in Firefox 4.

    0
  13. 13

    Tomek Paczkowski

    May 30, 2011 6:21 am

    I tried to correct #7, but my previous comment “was marked as spam”. I’ll just say, there’s an error in #7.

    2
  14. 14

    Tomek Paczkowski

    May 30, 2011 6:21 am

    I tried to correct #7, but my previous comment “was marked as spam”. I’ll just say, there’s an error in #7.

    0
  15. 15

    That 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”

    3
  16. 16

    That 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”

    0
  17. 17

    #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/

    4
  18. 18

    #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/

    0
  19. 19

    Florian Cargoët

    May 30, 2011 6:51 am

    Built-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

    1
  20. 20

    Florian Cargoët

    May 30, 2011 6:51 am

    Built-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

    0
  21. 21

    Never 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;

    3
  22. 22

    Never 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;

    0
  23. 23

    10. Undefined can (usually) be defined

    /* But */ typeof(anUndefinedVariable) == ‘undefined’; // always

    2
  24. 24

    10. Undefined can (usually) be defined

    /* But */ typeof(anUndefinedVariable) == ‘undefined’; // always

    0
  25. 25

    value == undefined is not the only way to determined defined-ness.

    You can also do: typeof value === ‘undefined’. I almost always use this way instead.

    1
  26. 26

    value == undefined is not the only way to determined defined-ness.

    You can also do: typeof value === ‘undefined’. I almost always use this way instead.

    0
  27. 27

    Wolfram Hempel

    May 30, 2011 8:28 am

    How 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…

    1
  28. 28

    Wolfram Hempel

    May 30, 2011 8:28 am

    How 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…

    0
  29. 29

    For #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.

    1
  30. 30

    For #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.

    0
  31. 31

    Really good article, I know JavaScript have some oddities, but not that many.

    0
  32. 32

    Really good article, I know JavaScript have some oddities, but not that many.

    0
  33. 33

    Really Very Good Article.. :) getting dipper into javascript . Thanks for sharing..

    0
  34. 34

    Really Very Good Article.. :) getting dipper into javascript . Thanks for sharing..

    0
  35. 35

    A 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.

    2
  36. 36

    A 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.

    0
  37. 37

    Patrick Corcoran

    May 30, 2011 10:42 am

    There 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.

    0
  38. 38

    Patrick Corcoran

    May 30, 2011 10:42 am

    There 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.

    0
  39. 39

    String 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.

    0
  40. 40

    regardless 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.

    3
  41. 41

    regardless 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.

    -1
  42. 42

    whatgoodisaroad

    May 30, 2011 8:46 pm

    It’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.

    3
  43. 43

    whatgoodisaroad

    May 30, 2011 8:46 pm

    It’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.

    1
  44. 44

    Wow, gr8 JS tips.
    very much useful. Thanks!

    0
  45. 45

    Wow, gr8 JS tips.
    very much useful. Thanks!

    0
  46. 46

    An array with only one key which value is 0 also equals FALSE. That is:

    [0] == false; // true

    0
  47. 47

    An array with only one key which value is 0 also equals FALSE. That is:

    [0] == false; // true

    0
  48. 48

    You should have skipped the last code example..

    1
  49. 49

    You should have skipped the last code example..

    0
  50. 50

    The 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.

    -3
  51. 51

    The 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.

    0
  52. 52

    Thanks, 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.

    0
  53. 53

    Thanks, 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.

    0
  54. 54

    #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.

    0
  55. 55

    #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.

    0
  56. 56

    Balázs Galambosi

    May 31, 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

    0
  57. 57

    Balázs Galambosi

    May 31, 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

    0
  58. 58

    Now i know JS oddities exist, i will verify these before tearing my hair ;)

    0
  59. 59

    Now i know JS oddities exist, i will verify these before tearing my hair ;)

    0
  60. 60

    My personal favorite:

    var foo = [0];
    console.log(foo == !foo); // true
    console.log(foo == foo); // true

    1
  61. 61

    My personal favorite:

    var foo = [0];
    console.log(foo == !foo); // true
    console.log(foo == foo); // true

    0
  62. 62

    One 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.

    2
  63. 63

    One 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.

    -1
  64. 64

    If you liked this article, I recommend http://wtfjs.com/ which is a blog dedicated to weird idiosyncrasies of JavaScript.

    1
  65. 65

    If you liked this article, I recommend http://wtfjs.com/ which is a blog dedicated to weird idiosyncrasies of JavaScript.

    0
  66. 66

    Awesome post, love the NaN == NaN example!

    0
  67. 67

    Awesome post, love the NaN == NaN example!

    0
  68. 68

    Christian Sciberras

    June 1, 2011 12:51 am

    Very interesting article, though, sadly, nothing new. Hope to see more “secret” quirks in the future.

    0
  69. 69

    Christian Sciberras

    June 1, 2011 12:51 am

    Very interesting article, though, sadly, nothing new. Hope to see more “secret” quirks in the future.

    0
  70. 70

    Nice stuff! :)

    0
  71. 71

    Nice stuff! :)

    0
  72. 72

    Great article, thanks for the helpful tips and it’s wonderfully written.

    0
  73. 73

    Great article, thanks for the helpful tips and it’s wonderfully written.

    0
  74. 74

    Very well written and nicely presented.

    0
  75. 75

    Very well written and nicely presented.

    0
  76. 76

    Durex, really? :D

    0
  77. 77

    Durex, really? :D

    0
  78. 78

    Oh, 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 === :)

    0
  79. 79

    Oh, 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 === :)

    0
  80. 80

    Graham De Young

    June 2, 2011 9:20 am

    The best, cross-browser way to test if a variable (foo) is defined is:

    if (typeof foo != ‘undefined’) {
    // foo is defined
    }

    1
  81. 81

    Graham De Young

    June 2, 2011 9:20 am

    The best, cross-browser way to test if a variable (foo) is defined is:

    if (typeof foo != ‘undefined’) {
    // foo is defined
    }

    0
  82. 82

    Graham De Young

    June 2, 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’.

    -1
  83. 83

    Graham De Young

    June 2, 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’.

    -1
  84. 84

    All js programmers need to read. Thanks.

    0
  85. 85

    All js programmers need to read. Thanks.

    -1
  86. 86

    Your 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

    2
  87. 87

    Your 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

    1
  88. 88

    This 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

    2
  89. 89

    This 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

    1
  90. 90

    Hi 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.

    -1
  91. 91

    very good article. thanks for sharing

    0
  92. 92

    Adrian Grigore

    June 8, 2011 7:29 am

    Great article! But may I suggest that you rename it to “further proof that Javascript is evil” ;-)

    0
  93. 93

    Just 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!

    1
  94. 94

    alert(/w{3,}/.test(‘Hello’)); // I receive false not true

    has this been addressed? I’m using FireBug in Firefox 5 for testing

    0
  95. 95

    0.1 + 0.2 !== 0.3 有趣~

    0
  96. 96

    All this time without knowing that is was possible to fake scope() :)

    0
  97. 97

    A 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/

    0
  98. 98

    Eric Georgiades

    July 30, 2013 4:25 pm

    I’ve been using JavaScript for years and while I’ve known some of the above and laughed about them, I am surprised to discover some for the first time.

    great article, thanks.

    0
  99. 99

    Good point about equality operator.
    One can read it in depth on:
    http://codefudge.com/blog/2014/03/23/javascript-equality-equals-equals-truthyness/

    0
  100. 100

    Bob, 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.

    2
  101. 101

    Bob, 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.

    0
  102. 102

    This 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.

    0
  103. 103

    This 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.

    0
  104. 104

    Yes, of course it’s a browser issue rather than a JS one, but since it affects only JS it’s relevant to this article.

    -1
  105. 105

    Mike Marynowski

    May 31, 2011 11:07 pm

    Hex 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.

    1
  106. 106

    Yes, of course it’s a browser issue rather than a JS one, but since it affects only JS it’s relevant to this article.

    -1
  107. 107

    Mike Marynowski

    May 31, 2011 11:07 pm

    Hex 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.

    1
  108. 108

    Patrick Corcoran

    May 30, 2011 12:02 pm

    It has nothing to do with JavaScript. This quirk would be exposed by any scripting language plugged into the browser.

    0
  109. 109

    Patrick Corcoran

    May 30, 2011 12:02 pm

    It has nothing to do with JavaScript. This quirk would be exposed by any scripting language plugged into the browser.

    1
  110. 110

    …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?

    1
  111. 111

    …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?

    -1
  112. 112

    Yeap, this is also a falsy. Thanks for sharing.

    -1
  113. 113

    Axel Rauschmayer

    May 31, 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

    0
  114. 114

    Yeap, this is also a falsy. Thanks for sharing.

    -1
  115. 115

    Axel Rauschmayer

    May 31, 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

    0
  116. 116

    Totally 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.

    0
  117. 117

    Totally 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.

    -1
  118. 118

    what’s wrong with you man?

    1
  119. 119

    My 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?

    2
  120. 120

    My 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?

    0
  121. 121

    Perhaps 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!

    -1
  122. 122

    Perhaps 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!

    0
  123. 123

    Perhaps 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.

    2
  124. 124

    Perhaps 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.

    0
  125. 125

    Bertold von Dormilich

    May 31, 2011 8:23 am

    parseInt(): [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.

    1
  126. 126

    Bertold von Dormilich

    May 31, 2011 8:23 am

    parseInt(): [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.

    0
  127. 127

    Axel Rauschmayer

    May 31, 2011 1:40 pm

    Any 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.

    0
  128. 128

    Axel Rauschmayer

    May 31, 2011 1:40 pm

    Any 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.

    0
  129. 129

    Every group includes these people :) Also, sarcasm is awesome, spite and anger are the bad qualities :)

    2
  130. 130

    Every group includes these people :) Also, sarcasm is awesome, spite and anger are the bad qualities :)

    0
  131. 131

    Damned right, I always forget that January actually 0…

    -1
  132. 132

    Damned right, I always forget that January actually 0…

    0
  133. 133

    The 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).

    2
  134. 134

    The 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).

    1
  135. 135

    No, native literals are not object instances. They are coerced to objects when you invoke methods on them.

    1
  136. 136

    No, native literals are not object instances. They are coerced to objects when you invoke methods on them.

    1
  137. 137

    I think you can also do

    if (!!foo) {
    // foo is defined
    }

    0
  138. 138

    Yes – this is JS data coercion in action. Thanks for sharing.

    0
  139. 139

    you could do:

    setTImeout((fn = (function(){

    })()), 1000);

    sould call a function hung off window called “fn”

    also:

    (!1 === false)
    (!” === true)
    (!0 === true)
    (!”) && console.log(‘I just ran’);
    (!1) && console.log(‘Hmmmm….’);

    0

Leave a Comment

Yay! You've decided to leave a comment. That's fantastic! Please keep in mind that comments are moderated and rel="nofollow" is in use. So, please do not use a spammy keyword or a domain as your name, or else it will be deleted. Let's have a personal and meaningful conversation instead. Thanks for dropping by!

↑ Back to top