I keep reading things saying "Object.keys is much faster than for..in", but in most tests I do (and in a bunch I find on jsperf.com), that is the opposite of the case. Object.keys seems to often be very fast compared to calling Object.hasOwnProperty on each element inside of a for..in, but it seems to have a lot of overhead and be much slower than for..in on small objects.
Some jsperf entries and my perf difference in Chrome: http://jsperf.com/object-keys-vs-for-in-for-values/8 (Object.keys 70% slower just getting an array of keys on small objects) http://jsperf.com/object-keys-vs-for-in-for-values/7 (Object.keys 80% slower iterating over values on small objects) http://jsperf.com/obj-property-iteration/3 (test earlier in the thread; for..in 20% slower on larger (100 member) object) These are all pretty contrived test cases, and running the same small code over and over again in a perf test seems to not necessarily translate well to an actual app running lots of different small bits of code at random (at least as far as V8's optimizer is concerned - perhaps it unrolls the small loops in the first test?), so I'm not completely confident from just those tests. At least in Chrome, we've seen very bad garbage collection hitches in V8, and using either closures or even a function made with Function.prototype.bind adds a lot of extra pressure to the heap, greatly increasing the frequency and/or cost of garbage collection stalls. We're working on a 3D WebGL engine, and the garbage collection stalls are very noticeable if they're happening with any frequency. Anyway, a bunch of random anecdotal evidence, but after converting all of our code to use for..in instead of closures passed to iterator functions, we saw much improved performance (primarily from untolerable 500ms garbage collect stalls every 10s or so down to acceptable <50ms garbage collect stalls at around the same frequency). It seems, at least currently for our project, if we're working with small data sets, in trusted code, for..in with no guards is the best performing (as well as arguably the simplest to read). If you're writing modules though, please always use Object.keys or a loop guarded with .hasOwnProperty to be safe, it really sucks when an external module breaks for no clear reason. Once we added a once-per-frame "for (var i in {}) throw 'some idiot extended Object.prototype';", we've been able to be much more confident in ensuring our for..in code is (relatively) safe. jimb On Feb 13, 8:47 am, Tim Caswell <[email protected]> wrote: > Since this is the nodejs list, I'm going to assume you're working in > node. In that case, Object.keys is built-in and it's really fast in > V8 (much faster than for .. in). Also if you want to share code with > the browser and it's not a mobile app (meaning it needs to support old > ES3 browsers), then it's easy and safe to add an Object.keys function. > It's not on the object prototype. > > function forEach(obj, callback, thisp) { > var keys = Object.keys(obj); > for (var i = 0, l = keys.length; i < l; i++) { > var key = keys[i]; > if (callback.call(thisp, obj[key], key, obj) break; > } > } > > Then to use this function, simply do: > > forEach(obj, function (value, key) { > // do something > }); > > If you want to preserve your "this" value, just pass it in as an > argument after the callback. The built-in Array.prototype.forEach > works just like this. If you're comfortable changing > Object.prototype, then put this function there (moving the first > argument to `this`). > > If you want to be able to break out of the loop, simply return true > from the callback. > > For older browsers, Object.keys can be implemented simply as: > > Object.keys = function (obj) { > var key, keys = []; > for (key in obj) { > if (!obj.hasOwnProperty) continue; > keys.push(key); > } > return keys; > }; > > > > > > > > On Mon, Feb 13, 2012 at 9:01 AM, Axel Kittenberger <[email protected]> wrote: > >> You could do : myobj.hasOwnProperty(key) But then if myobj is NULL it > >> will throw an error. > > > Unless nil suddendly has keys, it wouldn't go into loop anyway. > > > Personally I don't like forEach too much, since I cannot break from > > it, when I decide the rest is uninteresting. Or even return from the > > parents function. At least not without some > > oh-so-clever-but-ugly-misuse of exceptions. Why they didn't make the > > standard forEach in that returning false terminates the loop is beyond > > me, or even designed javascript so you can do "named returns", that is > > returning directly the closures parent, which only would work if the > > closure is not exported out of the function anyway. But honestly this > > is all off-topic to Node.js. To Node javascript comes with its quirks > > as it is, and is no language design project. > > > -- > > Job Board:http://jobs.nodejs.org/ > > Posting > > guidelines:https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines > > You received this message because you are subscribed to the Google > > Groups "nodejs" group. > > To post to this group, send email to [email protected] > > To unsubscribe from this group, send email to > > [email protected] > > For more options, visit this group at > >http://groups.google.com/group/nodejs?hl=en?hl=en -- Job Board: http://jobs.nodejs.org/ Posting guidelines: https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines You received this message because you are subscribed to the Google Groups "nodejs" group. To post to this group, send email to [email protected] To unsubscribe from this group, send email to [email protected] For more options, visit this group at http://groups.google.com/group/nodejs?hl=en?hl=en
