Sugar Arrays: Porting over JavaScript 1.6 Array methods
As of Firefox 1.5, there has been a new wide array of Array helpers that were included in JavaScript 1.6. That’s all fine and great, however there isn’t a single other browser on the market (as of this writing) that supports any of the new array methods (let alone JavaScript 1.6). What’s a developer to do?
Add Sugar
If you’re developing for todays grade A browsers, then you can count on being able to extend Array through it’s prototype. But, since I have a natural love toward things that are sweet, I’ve already done it for you with sugar and spice.
See the complete test specification document and download sources.
I used the Crock’s simple style of augmenting objects as a base to set up all my Array methods:
Class Augmentation
Function.prototype.method = function (name, fn) {
this.prototype[name] = fn;
return this;
};
The source includes each and all array methods that were added in JavaScript 1.6:
- every
- filter
- forEach
- map
- some
- indexOf
- lastIndexOf
Here is an example of forEach method pulled from the source file:
Array.prototype.forEach
Array.
method(
'forEach',
function(fn, thisObj) {
var scope = thisObj || window;
for ( var i=0; i < this.length; ++i ) {
fn.call(scope, this[i], i, this);
}
}
);
Self-Defense
As a preventative measure to safeguard against overriding existing native browser implementations (wow that was a mouthful), I added one conditional statement at the beginning of the source that checks if Array.prototype.forEach has already been defined. See below for an illustration:
conditional object check
if ( !Array.prototype.forEach ) {
// add sugar
}
The reason that I did not put a check for every other method in the implementation is that I figure if any browser hasn’t added forEach, they most likely didn’t add the rest. Likewise, if a browser manufacturer did implement forEach, I’m willing to put my money that they threw in the others as well.
Enjoy!




November 3rd, 2006 at 1:59 am
Reminds a bit of all the prototyping back in the days when IE6 got out (and thus backporting functions to the 5.x series).
Dustin for President! Very nice work!
November 3rd, 2006 at 3:37 am
Erik Arvidsson already did this perfectly well:
http://erik.eae.net/archives/2005/06/05/17.53.19/
November 3rd, 2006 at 7:03 am
..and so Andrea Giammarchi:
http://www.devpro.it/JSL/
November 3rd, 2006 at 7:47 am
[...] Link [...]
November 3rd, 2006 at 9:05 am
Dean and Kent,
Glad to hear it. I was searching around and couldn’t find anyone who had. At least it didn’t take too long. It made for an interesting 20 minute exercise. Erik and Andrea, good for both of you guys :) - (since I know the both of you might be headed toward this way soon enough).
Now if only
Node.prototypecan inherit fromArray.prototype…November 3rd, 2006 at 9:29 am
Excellent Dustin, thanks. I had no idea those others were out there either. This is educational as well. Thanks again for contributing to the community. It’s *greatly* appreciated.
November 3rd, 2006 at 11:29 am
Sweet!
November 3rd, 2006 at 12:24 pm
When’s the next screencast?
Those first 3 seemed to come out within 2 weeks of each other, but now it’s been almost 2 months. This post would have made for a good screencast.
November 3rd, 2006 at 2:25 pm
And another: http://www.nczonline.net/archive/2005/7/231
November 4th, 2006 at 4:00 am
Nice. Couldn’t you build the self-defence into the “augmenting objects” method? The code would look like this:
November 4th, 2006 at 1:20 pm
Doug, I suppose that wouldn’t hurt, although I don’t think I’ve ran into a problem personally of overriding existing prototypes.
November 4th, 2006 at 8:02 pm
Can someone tell me what the advantage is of adding methods to the prototype in Crock’s way instead of just adding them like Array.prototype.forEach = function(….); ?
November 5th, 2006 at 12:26 am
Hi Tommy,
I believe I deleted one of your comments from ealier without telling you. Mainly because you had posted code that was garbled by Wordpress (probably because your forgot to encode the html).
More importantly, to answer your question: They both do exactly the same thing. So really, it’s not that one is really better than the other, but with sugar you get the elegance of a classical OO approach, but with JavaScript.
Also by returning
thisin themethodmethod, you benefit from the cascade effect which allows you to continually add methods, one after another. Eg:November 5th, 2006 at 3:02 am
Dustin,
The point is that you then wouldn’t need to add the check code you describe in your Self-Defense section and the question of “why are you only checking forEach?” would go away because each additional method would be automatically checked (though I think you are correct in your argument that no vendor is likely to add forEach without the others or vice-versa).
Your sugar-adding code can then just consist of the unconditional chained calls to “method()”.
November 5th, 2006 at 10:57 am
Dustin,
Tnx for your explanation. Sounds convincing :)
November 7th, 2006 at 11:40 am
Dustin, you are always ahead of the game–well, ahead of me anyways. Cool stuff man!
Jim
November 11th, 2006 at 2:22 pm
Nicely done, however your indexOf implementation doesn’t seem to make use of the start parameter, should this not be used to initiate i in the for loop? Or am I missing something ?
November 13th, 2006 at 12:15 am
Lloyd, I’m not sure what you mean? This isn’t the same indexOf for strings, and I’ve tested this implementation on various test cases. It works just fine. Noticing that other implementations are written almost exactly the same confirms that it’s correct as well.
November 13th, 2006 at 12:15 pm
Yeah it works, but the Mozilla array.indexOf specs shows two parameters, the search element, obviously, and the fromIndex to start from, which you have half implemented.
Your code:
Should it not be:
?
November 13th, 2006 at 12:39 pm
Ah. I see now. Good catch. Thanks for spotting that.
November 19th, 2006 at 12:33 pm
[...] A quarta parte de hoje são alguns links sobre desenvolvimento: Controle de sessão e PHP, Modelo de orientação a objetos em PHP 5, Minikit: visual effect bag, Sugar Arrays: Porting over JavaScript 1.6 Array methods, Remote Scripting Transport Patent, Amberjack: JavaScript Site Tour Creator, 3D Rendering in JavaScript e 10 things you (probably) didn’t know about PHP. [...]
January 4th, 2007 at 5:37 am
Thanks
Keep up the good work :)
January 10th, 2007 at 9:49 am
Hi to all,
I just sent Dustin a lengthy mail about the prototypes, since I somewhere got the idea I didn’t find the reply box. Doh. That will teach me to surf with 30 tabs open lol.
I had a remark about indexOf that Si Lloyd already spotted, and a few other things were addressed. Most important part was the looping through the array indexes as done by forEach, every, some, filter and map.
What’s wrong with it? Nothing. But I like to code so my users can’t hurt themselves. So I like to build some sanity checking into everything. In this case, there is a flaw in the implementation that only creeps up when the programmer does stupid things.
Since even programmers can be stupid, I’d rather prevent ‘em from doing it. Now to the point. Suppose one does this:
Why one would do this, is beyond the point. In this case, Dustin’s implementations run through all the indexes from 0 to 1000000000, while only performing two actions. Not very efficient, and on my pc it took sometimes ages to finish.
My proposal is to loop through the Array object members. I admit, in the case of small arrays, this would be less efficient. But I couldn’t record any speed penalties, even not when doing the whole thing a few thousand times over again. And in the case above, my versions loops only the prototype members and the two indexes.
How I implemented it? Like this:
First of all, my versions is intended to work on any js implementation from version 1.2 and up. That means also outside browsers. So that’s why i use apply() instead of call(). The part with continue is not needed at the moment, but is a placeholder for debugging/logging code. Oh yeah, I called the function to be called name and declared pass as a variable somewhere before. So maybe this version would be better for Dustin’s audience:
Oh and please, please, please: no remarks about coding style. That’s each to his own I think. And after all, when my version gets compressed, it hardly is bigger than Dustin’s one (also compressed with same app). I just like to have more whitespace in my developping version for readability.
I also had another remark about not following the full specs in indexOf and lastIndexOf, but it’s a minor issue since almost nobody uses will those like that. I’m talking about using negative offsets. On the other hand, that’s also true for all the above ;).
Aaaaaaaaanyway, this has gotten already too lengthy. If someone wants to know, I post it here later.
January 10th, 2007 at 9:52 am
Ooops, typo =>
I also had another remark about not following the full specs in indexOf and lastIndexOf, but it’s a minor issue since almost nobody will use them like that. I’m talking about using negative offsets. On the other hand, that’s also true for all the above ;).
February 13th, 2007 at 12:12 am
oh,this looks something wrong.the code isn’t entirely.pls delete the up comment.
March 9th, 2007 at 2:53 am
[...] To briefly explain what’s going on, you’ll see that I’m using two of the JavaScript 1.6 Array extras called filter and map which allow me to essentially weed out the non-checked checkboxes, and then map those elements with their values. For cross-browser compatibility I used my own sugar arrays. [...]
March 10th, 2007 at 11:31 am
Am I the only one who finds
less than sugary sweet?
A function inside my “shortcut”? That’s behaving more like
or
in my opinion.
I took a few minutes to change the methods so they could be called as I would expect.
is sweeter than
no?
March 31st, 2007 at 5:22 pm
@JFSIII: your filter() is doing something different to Dustin’s. What you could do, however, which would be kind of neat, is have a filter that would work both ways, based on whether the formal parameter was a Function object or not. filter() should in general take a callable though - what if you wanted to filter an array of numbers to get rid of values outside the range 20-45, say?
May 15th, 2007 at 9:36 am
I fail to see the main difference between map() and foreach(). It appears to me that they could both be used to accomplish the same purpose.
June 7th, 2007 at 10:50 pm
@James,
Will you (or anyone) please point out the differences in behavior (results) between version of filter I posted and the one from Sugar Arrays?
I do like the idea a function as a parameter, though.