Explanation

The global forEach function allows us to enumerate any object according to its type.
If the object is array-like (has a length property) then we enumerate it like an array.
All other objects are enumerated using the standard for var x in y mechanism.

When enumerating over objects, the discovered keys are compared against Object.prototype.
If the key is defined on the Object object then it is not enumerated.
That means that you cannot enumerate the built-in methods like toString and valueOf.

The global forEach function will delegate the enumeration of functions to Function.forEach.
So, if you choose to enumerate over a Function object you will skip the built-in methods there too.

The Kick-Ass Bit

Although I’ve defined a forEach method on Function.prototype this is never called
by the global forEach function (except when you are enumerating functions).

I’ve provided this as a bonus feature.
Basically, by calling the forEach method on a function you can enumerate
an object and compare the keys with that function’s prototype.
That means that you will only enumerate custom properties of the object.
An example is required:

Comments (84)

It is very tempting to implement forEach on all kinds of objects. But it is not always clear what it iterates over. F.e. String.forEach could enumerate over characters, words or lines. It is better to implement methods that return arrays, and then iterate over the array. The method name then makes it clear what is iterated over, and your code is more generic, because you can do more with arrays than just iterating.

typeof this.prototype[key] == "undefined" can be written as this.hasOwnProperty(key)

What I like about this notation is that it places the iteration statement (forEach) on the left. When enumerating arrays with map etc the iteration statments end up on the right and the code becomes difficult to read. The temptation is to chain your iteration methods and you end up with unreadable code.

hasOwnProperty is not implemented in IE5.0. It would be a shame to exclude that browser for the sake of one line of code.

Good point about the String object. Maybe I’ll implement Christof’s split idea to support iteration of character data.

typeof this.prototype[key] == "undefined" || this.prototype[key] !== object[key] is a better approximation of hasOwnProperty. Although there is still the obvious edge-case and maybe you prefer the current behaviour.

because in the former, the “object.length” attribute is evaluated for each iteration, and counted every time it is accessed?
(That might just be for arrays, or HTMLCollections, or something. But I’m sure I’ve heard this.)

You could take this a step further and try to back-hack JavaScript 1.7’s iterators, the ultimate in polymorphism. You’d have a wrapper object that’d respond to foo.next() calls, then throw an exception when it’s spent, etc.

Probably overkill, I admit. But I’ve been playing with the new JS 1.7 stuff and it’s making me salivate.

@Andrew – foo.next() requires that you throw a StopIteraton error in order to terminate the loop. I implemented something similar and ended up hating it. It is really hard to debug JavaScript when you are throwing errors in nested closures that you are passing around. I still have one throw StopIteration statement left in my library, it is nicely contained but I still want to get rid of it.

@Anthony, you can’t do that as it’ll stop early if an array element is false or null.

@Kentaromiura, the speed up would be negligible compared to the time required for fetching the array element and calling the callback. And you’d have to either fetch the elements backwards (which is probably wrong and can be a lot slower, DOM methods are often optimized for forward iteration) or perform some arithmetic to get the correct element (which would take longer than the time saved). Premature optimization etc.

But, it’s actually better to write: for (var i = 0, length = object.length; i < length; ++i). Not because it’s faster but because it’s how forEach is defined (although, it’s probably not a great idea to rely on such subtlties).

It’s all my fault, I’m a sort of Optimization Maniac
because in my 486 every single optimization is a big improvement
so I’ve suggested the while solution instead of for
sorry for beginning this disgression ;p

It got hidden in all the talk about optimization, but I wasn’t suggesting storing the length as an optimization but because it’s the right thing to do. From the mozilla documentation:

The range of elements processed by forEach is set before the first invocation of callback. Elements which are appended to the array after the call to forEach begins will not be visited by callback. If existing elements of the array are changed, or deleted, their value as passed to callback will be the value at the time forEach visits them; elements that are deleted will have the value undefined.

Do you know of anything about the speed implications of instanceof in javascript? I use javascript quite a bit but have never looked into instanceof. I know in school we were always told to never use instanceof. We should always enumerate _whatever_ because instanceof is so slow. In this case however you are using instanceof for enumeration, (and what you have done here is really sweet) so I would like to know just how bad instanceof is.

@Wesley – in pure OO terms you shouldn’t use instanceof as type-checking is frowned upon. As far as JavaScript goes I am not aware of any speed issues. In this case, it only called once to determine which forEach method to use. It is not called inside any loops.

@Dean – sadly, yes. I’ve been toying around with some large array operations recently (.forEach, .some, .every on 10.000+ elements) and tried the new Array functions inside an 1.5 extension, speed decrease by more than 50%. Even on the simplest iterations. Either it’s a bug, or the builtins do some implicit type evaluations that end up being quite expensive.

By the way, I’d be glad if you could cover the new Destructuring Assignment in JS 1.7 after the FF 2.0 release. I’ve found that even many Python programmers don’t know how to use it properly, or even know that it exists.

@Nikola Klaric: I guess you don’t do an extra function call inside the loop in your non JS 1.5 code.
To call the callback function the JS-interpreter has to generate a new context for local variables, execute that function and then find out if the context can be freed or if it contains values that are still referenced. That is rather expensive compared to just entering the block of a for-loop.

@Christof: +1
Seems to be an issue: cost of executing “for” block N times is much lower then cost of N function invocations.

@Nikola:
Just wondering how much it takes to process 10.000+ elements. I have (not the most complex) use case where it takes 3 second for IE to process less then 1000 elements (grouping of elements by attribute, original source is array, target is object with array properties).

@Dean: I almost never read books about programming any more, though I’ve seen that The Man in Blue and {ppk} released one each recently, so I might order those two. (If you wrote a book I might be tempted to read that one too.)

@dean, it might be worth noting excplicitly in the source code that the order is important. First you must check for the existence of and define Array.forEach and only then define Function.prototype.forEach.

I had already got Array.forEach in my toolkit, and after reading this blog-entry decided to add your Function.prototype.forEach to the mix. I inadvertedly placed it above my old Array.forEach and then things started to behave strangely in Internet Explorer.

Very nice, especially the check for the over-riding custom for each. Does this code make prototyping array, even object are of little concern?
Regarding speed here is a page to test the speed of functions I just put up: jsSpeedTester. Enjoy and thanks again for some head scatching Dean.

This will let you do things like ‘hello’.forEach(print), but for the number you will have to do var ten = 10; ten.forEach(print) as well as forEach(10, print) and forEach(‘hello’, print). My initial idea was to produce something like 10.forEach(print) but couldn’t do it what I got get close.

Does this make sense to you guy’s or am I doing something competely wrong? Is it ok to do block() instead of block.call() inside of the String and Number method?

[…] Dean Edwards recently described a pretty cool technique for enumerating javascript objects, but (currently) it’s not appropriate for sparse arrays. In case you’re unfamiliar with sparse arrays (or I’m using the wrong term), in the language of the Mozilla documentation for Array.forEach, a sparse array is one that’s not “dense”. For example: […]

[…] Javascript’s new forEach() function. Thanks to Dean Edwards, there is a cross browser solution, that is extremely simple to use. There are some other new functions as well that I haven’t explored yet, but they are worth noting. […]

[…] The base2 core library is also quite useful in its own way. It includes things like my Base class and enumeration methods. I’ll document this library sometime in the future (it’s only little). For the time being I am only supporting the base2.DOM module and even then only if you are using the bind() method that I’ve demonstrated here. […]

Dean is there anyway to break out of the forEach? I wanted to use it for searching for a value in an array of objects but could not find a way to get it to “break” out of the loop. Had to revert to a for loop instead in the mean time. Not had enough tea to ponder it over enough properly yet.

Thanks for your reply. I am able to enumerate most everything, yes, except what I have mentioned above. Chances are that your code works and the problem lies between the chair and the keyboardCan you share some clues on how I should proceed?

Thanks for the reply Dean. Enumerating audioPlayer works, as expected, but the problem I have is to be able to get to audioPlayer.

I have a jsp page that includes js code and on loading said page, those script s will get executed and create objects (like audioPlayer and many more) and I am looking for a way of discovering them, i.e. enumerating them

[…] this sent me on the hunt to see if it was at all possible. A furious Google search led me to a comment by Dean Edwards (who else?). He suggested throwing yourself out of the loop and wrapping the throw in a try catch […]

[…] Re: What do you use instead of enum? On Oct 14, 5:15*am, Kenny <kentil…@gmail.com> wrote: > I wanted to do a state machine with symbolic states, but I see enum is > not part of the standard. I only have seven, do I just make seven vars > and hand enumerate? > > kt http://dean.edwards.name/weblog/2006/07/enum/ […]