Possible memory leak in Chrome
If you are writing an extension for Chrome, it is probably not a good idea to log everything since the browser does not have any limit on how many console messages to store.
My first Chrome extension!
Since Google Chrome for Mac now supports extensions I decided to write one. I called it Tessie Notifier and all it does is display the status of the latest Disqus build. At work, we have special, testing-only machine called Tessie that automatically runs all the tests after each repository commit. It then generates a nice little report page. So my extension loads the page, checks the status and updates a browser-action icon.

(The ball on the right; it is blue (image of Neptune) when all tests passed, orange (Sun) when there are failures and white (Eris) when Tessie is not available. Also its tooltip shows latest commit information and clicking on it will load the report page for you)
Development process is pretty nice and simple. There is only one configuration file to write—JSON-formatted manifest file—and everything else is basically HTML and JavaScript. If you are using background page, debugging your extension is just like debugging any other site on the web using WebKit development tools. And there is also no need to pack the extension and restart your browser every time you want to try it out.
As a conclusion, here is the complete source code: tessienotifier. Consider it only as a code sample since I doubt that the actual extension could be of any use to anybody who is not working at Disqus.
On commit messages
A list of things you should do when committing, and why you should do it.
On the modified prototypes in JavaScript
I wrote a small function that can be used to retrieve links to the unmodified built-in methods (useful when you are running code in the environment where built-in objects’ prototypes were modified).
var getbuiltin = function(obj, fn) {
var iframe, func;
iframe = document.createElement('iframe');
iframe.style.display = 'none';
document.body.appendChild(iframe);
func = iframe.contentWindow[obj].prototype[fn];
document.body.removeChild(iframe);
return func;
};
/* Example: */
Array.prototype.push = function() {
this[this.length] = 'B';
};
var A = new Array();
A.push('A'); /* ['B'] */
var B = new Array();
B.push = getbuiltin('Array', 'push');
B.push('A'); /* ['A'] */
It works in Chrome, Safari and Firefox but not in Internet Explorer. There, you can’t access any JavaScript objects via frame’s window object. In other words, iframe.contentWindow.Array is undefined.
Puzzled.
Update: Thanks to Sanjar, aforementioned getbuiltin.js works in IE now.
V8 sorting optimization
I am glad to hear that my patch to jQuery has been accepted and committed. The problem was that Sizzle relies on the comparison function to be fired but V8 does not fire the function if objects are equal to each other (i.e. if they point to the same object in the underlying structure).
[document, document].sort(cmp); // cmp will never be called
[document, window].sort(cmp); // cmp will be called once
By the way, jQuery development mailing list is really nice. I thought I am going to subscribe just to discuss this one ticket but I am still there, reading their discussions about the library development.
High-order map implementation in JavaScript
I was writing simple JavaScript the other day and, to make sure that my code works in all browsers, instead of using Array.map, I wrote a trivial map implementation myself. Then, just out of curiosity, I wrote two more implementations and posted them on StackOverflow to see what other fellow programmers think.
Here’s my original implementation, pretty simple:
var map = function(arr, func) {
var newarr = [];
for (var i = 0; i < arr.length; i++) {
newarr[i] = func(arr[i]);
}
return newarr;
};
My second implementation is my favorite, in terms of style, but I am not going to use it anytime soon because, although such approach is adequate and fast in such languages as Scheme, it is terribly slow without tail call optimization. Plus, as mentioned in the StackOverflow thread, concat function is too expensive to use it here.
var map1 = function(arr, func) {
if (arr.length === 0) return [];
return [func(arr[0])].concat(map1(arr.slice(1), func));
};
In my third implementation I used iterative recursion; it has no real advantages over the first method.
var map2 = function(arr, func) {
var iter = function(result, i) {
if (i === arr.length) return result;
result.push(func(arr[i]));
return iter(result, i+1);
};
return iter([], 0);
};
I received a few code samples after I posted my code chunks on the StackOverflow and below are interesting things I noticed.
What if obj.length property is not a positive number?
The code in SpiderMonkey makes sure that the obj.length is a positive number with bit manipulation. And although this works with strings and objects, it fails if value is a negative number.
"string" >>> 0; // 0
var obj = {}; obj >>> 0; // 0
-1 >>> 0; // 4294967295
So with SpiderMonkey approach, in case of negative obj.length value, we will initialize a huge array and try to iterate over it.
What about this inside a callback function?
My implementations don’t care about this object and this is probably a bad thing. The code from mikesamuel uses an empty object while the code in SpiderMonkey provides an optional parameter for this.
jQuery, as we see, does not care about that either.
Why jQuery flattens resulting array?
Here’s the line from jQuery source code that flattens result before returning it.
return ret.concat.apply( [], ret );
I don’t know why they do that but it may cause unexpected results if you want to generate an array of arrays.
$.map([1,2,3], function(i) { return [i, i + 1]; });
// Expected: [ [1,2], [2,3], [3,4] ]
// Returned: [1, 2, 2, 3, 3, 4]
My latest version
With all the knowledge I got from the StackOverflow thread mentioned above I wrote another version of map implementation.
var map = function(arr, func /*, context */) {
if (typeof(arr.length) != 'number' || arr.length < 0) {
throw new TypeError();
}
if (typeof(func) != 'function') {
throw new TypeError();
}
var mapped = new Array(arr.length);
var context = (arguments.length > 2 ? arguments[2] : {});
for (var i = 0; i < arr.length; i++) {
mapped[i] = func.call(context, arr[i]);
}
return mapped;
};
The code (with some trivial tests) is also on my github page.
Update: Jesse Farmer reminded that map is a special case of inject and thus can be implemented as a call to the latter. His code: http://gist.github.com/208582.