Sergio and the sigil

Guided Tour: jQuery - guard and default operators

Posted by Sergio on 2009-12-09
This post is part of a series called the Guided Tours.

I'm sure I'm not alone when I say that one of the best ways to improve our coding skills is by reading code written by someone else. Sometimes we don't realize how lucky we are to have so much source code at our fingertips, namely Open Source Software.

The guided tours

With this post I'll start another unbound series where I highlight some interesting piece of code that I studied. I'll share my notes and do my best to explain what I learned from it.

jQuery: Eating the elephant one bite at a time

I wouldn't dare to start things off with a complete overview of jQuery. It's a massive chunk of JavaScript and I'm afraid there isn't an easy entry point in the source code.

I chose to find parts of it that are relatively easy to explain separately from the rest and that contain something worth explaining. I'll do at least a few of those from jQuery but my plan is to not keep this series tied to jQuery or even JavaScript.

The code under the microscope

We're going to take a look at jQuery.fn.text(), which returns the textual content of all the elements in the jQuery wrapped set, combined in a single string.

Here's the code from jQuery version 1.3.2.

text: function( text ) {
  if ( typeof text !== "object" && text != null )
    return this.empty().append( 
	   (this[0] && this[0].ownerDocument || document).createTextNode( text ) 
	);

  var ret = "";

  jQuery.each( text || this, function(){
    jQuery.each( this.childNodes, function(){
      if ( this.nodeType != 8 )
        ret += this.nodeType != 1 ?
          this.nodeValue :
          jQuery.fn.text( [ this ] );
    });
  });

  return ret;
},

The text() function can be called with or without arguments, so initially it tries to detect if a string argument was passed to it, in which case it will be made the content of the elements in the jQuery object.

Be aware that in all methods defined inside jQuery.fn the value of this will be the current jQuery object.

The first thing that caught my attention was the following expression:

(this[0] && this[0].ownerDocument || document)

In the context of the code it's expected to return a DOM document object, but it's a boolean expression, isn't it? What gives?

Well, yes, it is a boolean expression. That leads me to explain a subtle but powerful difference between boolean operators in JavaScript to many other languages you may be more used to.

Guard and Default operators

The way I like to describe the boolean operators && and || is: They return the operand that short-circuited and resolved the expression. To put in a different way, when the JS interpreter detects that one of the operands has a value that makes the remainder of the comparison irrelevant, it stops right there and that operand (not necessarily true or false) becomes the result of the boolean expression.

Truthy and Falsy: In the context of a boolean expression, any value in JavaScript has a boolean meaning. It's actually easy to memorize which mean which. The values that are treated as false are: false, null, undefined, 0, "" (empty string), and NaN. We call them falsy. Everything else is treated as true and we call them truthy.

Here are some examples:

ABA && B
false123false
null123null
01230
undefined123undefined
undefinednullundefined
123nullnull
123456456
123"text""text"
"text"truetrue
ABA || B
false123123
null123123
0123123
undefined123123
undefinednullnull
123null123
123456123
123"text"123
"text"true"text"

Because of the above behavior, these boolean operators are often used as Guard or Default operators. The guard operation is commonly used when you want to avoid a null or undefined reference error:

//someObj can be null. text will also be null in that case.
var text = someObj && someObj.toString();

Which is a shorthand for:

var text = null;
if (someObj !== null) {
  text = someObj.toString();
}

The default operation is arguably a much more common occurrence. We see it a lot when functions support optional arguments with default values. When a value is not given for a function parameter, it becomes undefined. We can detect that and give a default value like this:

function addAll(numbersArray, step) {
  step = step || 1;
  var sum = 0;
  for (var i = 0; i < numbersArray.length; i += step) {
    sum += numbersArray[i];
  }
  return sum;
}
addAll([1, 2, 3, 4, 5, 6]); // ==> 21
addAll([1, 2, 3, 4, 5, 6], 3); // ==> 5

In the above example, the step parameter is optional. Not providing it would cause a problem if we hadn't defaulted it to one right at the beginning of the function.

Wow. We sure covered a lot of stuff just to explain a simple boolean expression. The good news is that we will see a lot of that in the jQuery code (or in pretty much any decent JS code base) so it's good to understand it well.

Back to our original expression.

(this[0] && this[0].ownerDocument || document)

Armed with our new understanding we can finally read this expression as: If this.ownerDocument exists I want that, otherwise just give me the global document object. This returned DOM document object will be the owner document of new text value being inserted.

What about the rest of that function

It's funny that a tiny bit of that function became this long post. But the remainder of the function, in its majority, isn't really all that interesting in terms of JavaScript. It's mostly boring DOM navigation, done recursively. If you know how to use the jQuery.each() utility function, you can figure out that code on your own.

Our time here is up and we have a whole lot more of code sightseeing to do.

Test-Driving a new feature for JavaScript

Posted by Sergio on 2009-11-12

Talk: Stop Programming JavaScript by Luck

Posted by Sergio on 2009-11-10

Last Saturday I had the pleasure to present a JavaScript talk at the Iowa Code Camp. The talk was Stop Programming JavaScript By Luck and it tries to highlight some of the most puzzling differences from your mainstream programming language (read: C#, VB, Java.)

I'd like to thank all that came to the talk and the Code Camp organizers for inviting me. Here are the video recording and the slide deck.

The video

 

And the slide deck.

CouchDB Presentation

Posted by Sergio on 2009-10-01

In this month's Chicago ALT.NET meeting we will be taking a look at Apache CouchDB. I quote from the official site:

Apache CouchDB is a document-oriented database that can be queried and indexed in a MapReduce fashion using JavaScript. CouchDB also offers incremental replication with bi-directional conflict detection and resolution.

CouchDB provides a RESTful JSON API than can be accessed from any environment that allows HTTP requests.

Get Comfy With CouchDB

6:00 pm
Pizza and networking time

6:30 pm

CouchDB is one of the more mature schema-less map/reduce object dbs out there. In this talk we'll cover the basics of what CouchDB is, and why it's cool, and then we'll run through a sample application. The application will show off LINQ to Couch, basic persistance, views and full-text search with CouchDB-Lucene.

Alex Pedenko has been in software development for about 13 years, starting off on Borland Delphi, then spending about 4 years in Java and finally making the switch to .net around '03

Currently, he is the director of software architecture and chief architect at a healthcare services company. He has used that role as an opportunity to inject some modern ideas into an otherwise lagging industry, moving the company from a classic "giant web-app strapped to an even more giant db", to a distributed, service-oriented environment utilizing RESTful services, and rich-client applications.

Alex is also involved in a number of Open Source projects like Bistro and NDjango, and the .net side of CouchDB via Divan and LoveSeat

JavaScript and its love for zeroes

Posted by Sergio on 2009-09-19
This post is part of a series called JavaScript Demystified.

Answer quick. Do you know what date is being created here?

var year = '2009', month = '09', day = '01';
var date = new Date( 
             parseInt(year),
			 parseInt(month),
			 parseInt(day)
			 );	

At first glance, it wouldn't surprising that someone guesseed September 1st 2009. However, I'd not be writing this post if that was the correct answer, right?

There's an interesting and tricky thing with the JavaScript parseInt function: it can parse strings with a numeric value in the decimal radix, but also in other radices. See the following examples.

//passing the radix explicitly
parseInt('1011', 10); // ==> 1011
parseInt('1011',  2); // ==> 11
parseInt('1011',  8); // ==> 521
parseInt('1011', 16); // ==> 4113

Maybe you thought that if you didn't pass the radix, then it would default to 10 because it's the obvious behavior. Well, no. In JavaScript the default behavior is to try to identify one of the literal formats and interpret that. So here's that in action:

//leaving JavaScript on its own
parseInt('1011'); // ==> 1011 (decimal literal)
parseInt('0x12'); // ==> 18   (hexadecimal literal)
parseInt('0511'); // ==> 329  (octal literal)
parseInt('0182'); // ==> 1    (whaaaa?!?!)

If you are familiar with the literal notation for integer numbers in JavaScript, and after I explained the default behavior of parseInt, then you probaly understood the results shown above. Well, maybe the last one deserves some comments.

When JavaScript is parsing the string, if it finds a digit (number or alpha) that is invalid in the chosen radix, it stops right there and parses only the portion of the string that comes before that digit. So, since we started '0182' with a leading zero, the octal radix is assumed. Then, because 8 is not a valid octal digit, only '01' will be parsed, which becomes 1.

Tip #1: If there's any chance the string value you plan to parse into an integer number has a leading zero (or a less likely 0x,) then be safe and pass the radix parameter to your parseInt call. If you're extra paranoid, then always pass the radix.

Back to our original question

Armed with the clarification made above, we can expand our example like this:

//given:
var year = '2009', month = '09', day = '01';
// then the following statement:
var date = new Date( 
         parseInt(year),
         parseInt(month),
         parseInt(day)
         );	
//...is equivalent to:
var date = new Date( 
         2009,
         0,  // ===> oopsie
         1
         );	

Hmmm, a zero in the month parameter. Will we have an error here? No, here comes the second potential surprise of this post.

Tip #2: When creating a new date using new Date(year, month, day), the month parameter, and only the month parameter is zero-based (0 to 11).

So, in case the tips and the picture in this text were not enough to help you guessing the date being created, here goes another completely gratuitous one with the answer.