More on JavaScript prototypes and for..in

Posted in Development, JavaScript, Web

Liorean disagrees with the rant I made a fortnight ago. He thinks that Array.prototype is impolite to muck with and gives a couple reasons why. I understand where he’s coming from, but I’m not quite convinced that the examples he cites are deal‐breakers.

(N.B.: What follows is the opinion of one man. This section is non‐normative.)

The JavaScript for..in loop is broken. It’s not broken in the scope of what it was designed for, but it’s broken in the way that most people expect it to work.

It’s extremely useful for object introspection, which I’d guess was its original purpose, but its drawbacks are such that it can’t reliably be used for anything else. It enumerates properties that occur anywhere in an object’s inheritance chain, but it does not give script writers any way to hide particular properties from enumeration. (Yes, you can use hasOwnProperty in your loop. But good luck getting any third‐party scripts you use to do the same.)

This is why we’ve tentatively agreed on Object.prototype as the no‐fly zone. This is an ugly compromise that makes me queasy, because it takes away a bunch of really cool possibilities, but it’s the best we can do.

Brendan Eich has identified this as one of the weaknesses of JS1 — that sharing namespaces requires “cooperation and benign code.” Of course, as we’re illustrating, each coder has his own definition of benign. Packages are just one of the many ways that JavaScript 2 is supposed to facilitate “programming in the large.”

(Google won’t tell me whether true hashes are planned in JS2, but I desperately hope so. Brendan, care to comment?)

I’m not calling for a moratorium on for..in. I’m simply saying that anyone who uses for..in needs to be aware of what she is asking for and what she might receive in return. It’s not JavaScript’s version of foreach. Anyone who treats it that way is inviting trouble.

Of course, this is really just a philosophy difference: you say extending Array.prototype is impolite, but I say assuming Array.prototype hasn’t been extended is naive. Array isn’t your object any more than it’s mine; it’s a community property, so a script writer needs to know that his array might have more properties than the few he has explicitly set.

I agree with David Lindquist on this one:

[A]s long as we are forbidding things, I would much rather discourage the use of for/in than get rid of the über‐handy Array extensions!

If I had to give up for..in in order to gain Prototype’s each method, I’d do so in a heartbeat. The minor hassle of implementing my own hashes would be forgotten in the face of all the keystrokes I’d save. Do you know how happy I am now that every fifth line in my code isn’t for (var i = 0; i < arr.length; i++) {?

Some people disagree. Some people disagree very loudly. Fine! Our libraries are incompatible because our definitions of benign are incompatible. I’m not trying to convert you; I’m just trying to make you stop calling me a heathen. Use whatever code makes you happy.

I’m not saying that these issues aren’t important, but aren’t there more constructive ways to channel our emotions here? If half a dozen of the world’s foremost JavaScript rockstars walked into a conference room, they’d walk out twenty minutes later with a bulletproof implementation of hashes in only nine lines of code. Why haven’t we done this yet?