31.7.06

Fundamentals of Confusion

(Tricky, Tricky JavaScript - part three)

To those who have hurt their heads scratching them.

1. Functions are Objects. This one is easy. You can pass them around just like a Boolean or a String. It can be returned by another function:

function x(){
return function (){ return []; }
}

x()(); // returns []

x(); // returns a function

setTimeout(function (){
doStuff();
}, 500);


Anonymous functions are very useful in situations like the one above. Why create another function in the global scope? You have the added benefit of being able to use closures.



2. Not all Comparisons are Equal. This one can be confusing. If you're not using strict comparison, code coercion will take place. However, if you're directly testing an object, the results can be counter-intuitive:

var A = !![];


Double negation is a boolean coercion. This bit says should be read as "does the object exist?". A is true. The same can be said about [] ? true : false; or if ([]){ }

if ([] == 0){ }


This is where it can get you. The comparison evaluates to true, but only because the array is equivalent to zero. The coercion could be interpreted as looking at the array's length. Note that if (0) {} is false. Also, be on the lookout for this:

if ([0] == 0) { }
if (['0'] == 0) { }


These evaluate to true too! The lesson is, forget coercion. If you compare to zero, null or underfined, use strict comparison. If you want to see if an array is empty, use if ([].length) { }. Enough of arrays, though.

var B = (NaN == NaN);
var C = (undefined == undefined);


Something that is not a number can be anything but a number. So B is false. Something undefined is just that: undefined. They're all the same. So C is true



3. Closures define environments, not "snapshots". When a closure is created, it keeps a reference to the variables in scope when the closure was created, not necessarily the values!

  var c = {a:true, b:false};
var m;
for (var n in c){
m[n] = function () {return c[n];};
}
var D = m['a']();


Did you think a was true? It's not. The closure keeps a reference to c and n, not their values. When m['a'] is declared, it only declares a function. There is no declaration of what the function contains. However, when the function is called, it looks for the value of n, which is false because it stays at the last state of its iteration. The same can be said if a ifelse loop is used instead

In case you missed it, see part one and part two of this "confusion" series, aimed at the ones who jumped more recently on the JavaScript wagon.

No comments: