Ext JS iterator functions
July 23, 2009 by Ed Spencer · 6 Comments
Ext JS has a number of handy iterator functions. Some, like Ext.each, you probably already know about, but there are a few others lurking around which can be useful in saving yourself a few lines of code. First, let’s recap Ext.each:
Ext.each
Ext.each applies a function to each member of an array. It’s basically a more convenient form of a for loop:
var people = ['Bill', 'Saul', 'Gaius'];
//using each to detect Cylons:
Ext.each(people, function(person, index) {
var cylon = (index + 1) % 2 == 0; //every second man is a toaster
alert(person + (cylon ? ' is ' : ' is not ') + 'a fraking cylon');
});
//is the same as
for (var i=0; i < people.length; i++) {
var person = people[i];
var cylon = (index + 1) % 2 == 0; //every second man is a toaster
alert(person + (cylon ? ' is ' : ' is not ') + 'a frakin cylon');
};
Ext.iterate
Ext.iterate is like Ext.each for non-array objects. Use it wherever you would normally use a for .. in loop:
var ships = {'Bill': 'Galactica', 'Laura': 'Colonial One'};
Ext.iterate(ships, function(key, value) {
alert(key + "'s ship is the " + value);
});
//is the same as
for (key in ships) {
var value = ships[key];
alert(key + "'s ship is the " + value);
}
Using Ext.iterate with an array is the same as calling Ext.each. Each and Iterate both take an optional third parameter, which is the scope to run the function in. Another advantage over using the for construct is that you can easily reuse the same function:
var myFunction = function(item, index) {
//does some clever thing
}
Ext.each(people, myFunction);
Ext.each(['another', 'array'], myFunction);
Ext.pluck
Ext.pluck grabs the specified property from an array of objects:
var animals = [
{name: 'Ed', species: 'Unknown'},
{name: 'Bumble', species: 'Cat'},
{name: 'Triumph', species: 'Insult Dog'}
];
Ext.pluck(animals, 'species'); //returns ['Unknown', 'Cat', 'Insult Dog']
Ext.pluck(animals, 'name'); //returns ['Ed', 'Bumble', 'Triumph']
Ext.invoke
Invoke allows a function to be applied to all members of an array, and returns the results. Using our animals object from above:
var describeAnimal = function(animal) {
return String.format("{0} is a {1}", animal.name, animal.species);
}
var describedAnimals = Ext.invoke(animals, describeAnimal);
console.log(describedAnimals); // ['Ed is a Unknown', 'Bumble is a Cat', 'Triumph is a Insult Dog'];
Ext.invoke performs a similar job to Ruby’s collect method in making it easy to transform arrays. Any additional arguments passed to the Ext.invoke call will be passed as arguments to your function, in this case the describeAnimal function. Obviously your functions will be much more grammatically accurate than mine.
Ext.partition
Ext.Partition splits an array into two sets based on a function you provide:
var trees = [
{name: 'Oak', height: 20},
{name: 'Willow', height: 10},
{name: 'Cactus', height: 5}
];
var isTall = function(tree) {return tree.height > 15};
Ext.partition(trees, isTall);
//returns:
[
[{name: 'Oak', height: 20}],
[{name: 'Willow', height: 10}, {name: 'Cactus', height: 5}]
]
The partition call above returns a 2-dimensional array with the first element containing all of the items for which the function returned true (tall trees in this case), and the second containing items for which the function return false.
Math functions
Finally, we have some simple math-related functions:
var numbers = [1, 2, 3, 4, 5]; Ext.min(numbers); //1 Ext.max(numbers); //5 Ext.sum(numbers); //15 Ext.mean(numbers); //3
While the built in functions don’t cater for all situations, they’re useful to have and to know about, and usually offer a more elegant approach than using the ‘for’ keyword.
Nice post, too!
Didn't know all of those methods.
Which I don't like about these methods is the fact, that Ext doesn't add those methods to the object classes you perform those methods on. So, this is pretty much PHP style.
I like more Prototype JS's and therefore Ruby's approach to add methods as 'each' directly to the Array class, which allows you to write [1, 2].each().
That's why I actually like to use Ext JS with the Prototype JS adapter.
I guess I'll write an Ext extension one day that adds such 'shortcuts' for the Ext methods to their respective class and removes the need for the Prototype JS dependency in my applications. Shouldn't be a big thing.
I also prefer Ruby's style of chaining method calls together, but sadly it can't be done safely in JavaScript, as augmenting Object breaks the "for key in values" construct.
I think it can be ok to do that, so long as the implications are understood. I tend to stick to the side of caution though and not augment Object at all. Ext JS is very good at respecting that approach also.
If you do write the extension you mention, be sure that everyone using it understands what the implications are
Strictly speaking, nobody should mess around with JavaScript Object. Leave it as is.
ExtJS approach is more professional.
I’m wondering why Ext adds the single `remove` method to Array.prototype? Extending Array or Function is safer than extending Object w/ respect to `for in`, but is a bit invasive for a library to do. There’s a case for a really developer-friendly library like prototype to make enumeration easier, but that’s not Ext so why pollute Array for just a single method? Is this just a mistake from the early days?
@rob agreed – for clarity I was referring to the style of code produced with Ruby’s built in enumerable functions, it’s secondary to global object pollution concerns though.
@mike as you say, augmenting Array is safe compared to augmenting Object because you don’t run ‘for … in’ on an array (unless you’re crazy). I’m not sure when it was added in but can’t really see a problem with it. Not sure I’d call it a ‘mistake’ either if it doesn’t have the negative consequences that augmenting Object has.
Always excellent to read pages like this. Bright & helpful! Thanks a lot