Object.prototype is Verboten?

javascript, prototype

Solution

The fact is, it's fine as long as you know what you're doing and what the costs are. But it's a big "if". Some examples of the costs:

You'll need to do extensive testing with any library you choose to use with an environment that augments `Object.prototype`, because the overwhelming convention is that a blank object will have no enumerable properties. By adding an enumerable property to `Object.prototype`, you're making that convention false. E.g., this is quite common:

var obj = {"a": 1, "b": 2};
var name;
for (name in obj) {
    console.log(name);
}

...with the overwhelming convention being that only "a" and "b" will show up, not "getProperties".

Anyone working on the code will have to be schooled in the fact that that convention (above) is not being followed.

You can mitigate the above by using `Object.defineProperty` (and similar) if supported, but beware that even in 2014, browsers like IE8 that don't support it properly remain in significant use (though we can hope that will change quickly now that XP is officially EOL'd). That's because using `Object.defineProperty`, you can add non-enumerable properties (ones that don't show up in `for-in` loops) and so you'll have a lot less trouble (at that point, you're primarily worried about name conflicts) — but it only works on systems that correctly implement `Object.defineProperty` (and a correct implementation cannot be "shimmed").

In your example, I wouldn't add `getProperties` to `Object.prototype`; I'd add it to `Object` and accept the object as an argument, like ES5 does for `getPrototypeOf` and similar.

Be aware that the Prototype library gets a lot of flak for extending `Array.prototype` because of how that affects `for..in` loops. And that's just `Array`s (which you shouldn't use `for..in` on anyway (unless you're using the `hasOwnProperty` guard and quite probably `String(Number(name)) === name` as well).

...if the V8 people do it, who am I to say they're wrong?

On V8, you can rely on `Object.defineProperty`, because V8 is an entirely ES5-compliant engine.

Note that even when the properties are non-enumerable, there are issues. Years ago, Prototype (indirectly) defined a `filter` function on `Array.prototype`. And it does what you'd expect: Calls an iterator function and creates a new array based on elements the function chooses. Then ECMAScript5 came along and defined `Array.prototype.filter` to do much the same thing. But there's the rub: Much the same thing. In particular, the signature of the iterator functions that get called is different (ECMAScript5 includes an argument that Prototype didn't). It could have been much worse than that (and I suspect — but cannot prove — that TC39 were aware of Prototype and intentionally avoided too much conflict with it).

So: If you're going to do it, be aware of the risks and costs. The ugly, edge-case bugs you can run into as a result of trying to use off-the-shelf libraries could really cost you time...

Problem

RECAP: Ok, it's been a while since I asked this question. As usual, I went and augmented the `Object.prototype` anyway, in spite of all the valid arguments against it given both here and elsewhere on the web. I guess I'm just that kind of stubborn jerk. I've tried to come up with a conclusive way of preventing the new method from mucking up any expected behaviour, which proved to be a very tough, but informative thing to do. I've learned a great many things about JavaScript. Not in the least that I won't be trying anything as brash as messing with the native prototypes, (except for `String.prototype.trim` for IE < 9). In this particular case, I don't use any libs, so conflicts were not my main concern. But having dug a little deeper into possible mishaps when playing around with native prototypes, I'm not likely to try this code in combination with any lib. By looking into this prototype approach, I've come to a better understanding of the model itself. I was treating prototypes as some form of flexible traditional abstract class, making me cling on to traditional OOP thinking. This viewpoint doesn't really do the prototype model justice. Douglas Crockford wrote about this pitfall, sadly the pink background kept me from reading the full article. I've decided to update this question in the off chance people who read this are tempted to see for themselves. All I can say to that is: by all means, do. I hope you learn a couple of neat things, as I did, before deciding to abandon this rather silly idea. A simple function might work just as well, or better even, especially in this case. After all, the real beauty of it is, that by adding just 3 lines of code, you can use that very same function to augment specific objects' prototypes all the same. I know I'm about to ask a question that has been around for quite a while, but: Why is Object.prototype considered to be off limits? It's there, and it can be augmented all the same, like any other prototype. Why, then, shouldn't you take advantage of this. To my mind, as long as you know what you're doing, there's no reason to steer clear of the Object prototype. Take this method for example: ``` if (!Object.prototype.getProperties) { Object.prototype.getProperties = function(f) { "use strict"; var i,ret; f = f || false; ret = []; for (i in this) { if (this.hasOwnProperty(i)) { if (f === false && typeof this[i] === 'function') { continue; } ret.push(i); } } return ret; }; } ``` Basically, it's the same old `for...in` loop you would either keep safe in a function, or write over and over again. I know it will be added to all objects, and since nearly every inheritance chain in JavaScript can be traced back to the `Object.prototype`, but in my script, I consider it the lesser of two evils. Perhaps, someone could do a better job at telling me where I'm wrong than this chap, among others. Whilst looking for reasons people gave NOT to touch the `Object`'s prototype, one thing kept cropping up: it breaks the `for..in` loop-thingy, but then again: many frameworks do, too, not to mention your own inheritance chains. It is therefore bad practice not to include a `.hasOwnProperty` check when looping through an object's properties, to my mind. I also found this rather interesting. Again: one comment is quite unequivocal: extending native prototypes is bad practice, but if the V8 people do it, who am I to say they're wrong? I know, that argument doesn't quite stack up. The point is: I can't really see a problem with the above code. I like it, use it a lot and so far, it hasn't let me down once. I'm even thinking of attaching a couple more functions to the Object prototype. Unless somebody can tell me why I shouldn't, that is.

Original source