« Array Extras | Main | Google Live Search »

Object.prototype is verboten

It is not seldom that you see people messing with Object.prototype. This is very bad because it breaks the object-as-hash-tables feature in javascript. Basically, the following is a very common scenario:

var obj = {a: "A", b: "B", c: "C", d: "D"};
for (var key in obj) {
   doSomething(key, obj[key], obj);
}

if ("b" in obj) {
   doSomethingElse();
}

If someone modified the Object.prototype the for in loop would include any fields you’ve added.

So let me say it in plain English: Object.prototype is forbidden and should be treated as sealed / constant / final.

PS. There are other issues with using objects-as-hash-tables in js, like for example toString, valueOf and others are not enumerated. If you need a totally fail safe hash table you need to implement that yourself. I leave that as an excercise to the readers (you can use the object-as-hash-table as a start).

This entry was posted on Monday, June 6th, 2005 at 22:13 and is filed under JavaScript, Web. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

98 Responses to “Object.prototype is verboten”

  1. Dean Edwards Says:
    June 12th, 2005 at 16:21

    Hear hear!

  2. Nicholas Says:
    June 22nd, 2005 at 20:11

    Always has to be on dissenter in the group, right? I think just like everything, Object.prototype has it uses. Granted, some people use it incorrectly, but really it can be very useful is used correctly (that is, to help with inheritance).

    That people try to use Object.prototype for anything other than inheritance is a little odd to me, and that’s typically where you run into trouble. My general rule of thumb: only functions go on a prototype, actual values go on the object itself.

    Just my $0.02

  3. Erik Arvidsson Says:
    June 25th, 2005 at 12:47

    Why would you use Object.prototype for inheritance? It makes more sense to use YourConstructor.prototype for this.

    Personally I put everything except mutable objects on the prototype of the constructor.

  4. Jan! Says:
    July 5th, 2005 at 20:16

    So if the String object doesn’t have the trim() method, and I want to add it to all strings, even ones that are already live, how would I do that?

  5. Erik Arvidsson Says:
    July 5th, 2005 at 23:59

    Jan: The String.prototype is safe to modify. Not many people use for in loops over string objects (or the in operator for that matter).

    String.prototype.trim = function () {
    return this.replace(/^\s+|\s+$/g, “”);
    };

  6. Julien Couvreur Says:
    July 7th, 2005 at 17:40

    What about removing/deleting all the extra methods that you don’t need, if you need a pure association table? I’m not sure what would be the best way of writing that up though. Any ideas?

  7. Erik Arvidsson Says:
    July 7th, 2005 at 18:07

    Julien: If you need a hash/associative array then use Object and not Array.

  8. IE7 and script.aculo.us Says:
    July 11th, 2005 at 00:12

    [...] head over to script.aculo.us/ and grab a fresh
    version from the SVN repository.

    Erik was right. I hope that the modified Prototype library is released soon because I quite lik [...]

  9. Jon Casey Says:
    July 20th, 2005 at 20:47

    Just wanted to say, it may be in best interest that any library should work with or with out an Object.prototype being added?

    Yes, it is a nice gesture, to not start off your codebase by interupting the Object.prototype.. BUT, any user that wants to incorporate their own prototype additions should not be denied access..

    In short:

    var object = new Object();
    for(var key in object){
    if(!(key in Object.prototype)){
    // do some stuff SAFELY!
    }
    }

  10. Erik Arvidsson Says:
    July 20th, 2005 at 22:45

    Jon: I’d rather not do that. If people want to modify a common supper class they should create their own base class.

    function MyObject() {}
    MyObject.prototype.thisIsSage = …;

    Adding the test you are suggesting every time is just asking for trouble.

  11. Jon Casey Says:
    July 21st, 2005 at 01:18

    Erik: Could you explain any troubles that would present themselves with the following code?

    I myself rarely ever have used the for..in loop for enumeration;

    Yet, as high-level programmers, should we not write code as efficiently as possible and make it as “bullet-proof” as possible?

    The mentioned code bit above is limited.
    But, any for..in loop that I would put in a Super-Library
    would do some small EXTRA bug-proof testing, to be assured any other has not tampered w/ such.

    But, I am speaking as a head developer for developers of highly deployed government client/web applications.

  12. Jon Casey Says:
    July 21st, 2005 at 01:19

    sorry meant the “above” code! not “following code” spacer

  13. Erik Arvidsson Says:
    July 21st, 2005 at 11:13

    The in operator and for in loops are used a lot since they are used to iterate over items in hashes and hashes are used a lot for lookup tables, caches and what not. Adding the test not only makes the code a lot harder to read, it also slows it down.

    Making things as bullet-proof as possible is not usually a good idea in interpreted dynamic languages because it adds too much overhead. Do you typecheck all your arguments in all your methods? Do you type check all your fields? Just a simple line as this would require a few tests:

    obj.method()

    Someone might have changed “method” so that it isn’t a Function any more or even worse removed obj.

    You have to put some restriction on the use and I’m all for banning changes to Object.prototype.

  14. Jon Casey Says:
    July 21st, 2005 at 14:29

    I can understand a small hit in performance, yet, find them barely measurable in my test cases.

    “Do you type check all arguments?” No, yet often, some manipulations must be performed to alter, or be assured the proper type was sent, or throw Error for improper arguments/arguments.length required.

    “Do you type check fields?” Validation may be required on MANY of them, but typically the areas are already constrained.

    Often for .. in loop would be done as you mentioned for certain needs, even just doing the simple:
    if(typeof o[key] != ‘function’) // .. process
    can eliminate 90% more complaints, and ease wider compatibility.

  15. Erik Arvidsson Says:
    July 21st, 2005 at 20:09

    Jon: This very common expression

    s in obj

    becomes the very cumbersome

    s in obj && s != a && s != b && s != c …

    The performance issue is negligable. The increase is complexity on the other hand is unacceptable.

    I just cannot justify modify Object.prototype. I agree that there are a few cases where one might want to modify Object prototype; isEmpty, getKeys and getValues as well as map, filter and other list type methods comes to mind. But for a real world API these needs to be static methods instead.

  16. Jon Casey Says:
    July 21st, 2005 at 20:54

    I agree on not modifying it by default.
    Just wondered if this could be a stronger way to enumerate.

    for (var p in o)
    if (!(p in Object.prototype))
    this.add(p,o[p]);

    Anyhow, great work, it is nice to see someone working along the same paths.

  17. Randy Reddig Says:
    July 23rd, 2005 at 03:46

    Modifying an object’s prototype is fine. The caveat is that you need to put an extra test into your for loops. The test is done with hasOwnProperty(), which unfortunately is unsupported in Safari/WebKit.

    To wit:

    if( !Object.prototype.hasOwnProperty ) {
    Object.prototype.hasOwnProperty = function( property ) {
    try {
    var prototype = this.constructor.prototype;
    while( prototype ) {
    if( prototype[ property ] == this[ property ] ) {
    return false;
    }
    prototype = prototype.prototype;
    }
    } catch( e ) {}
    return true;
    }
    }

    Object.prototype.extend = function( object ) {
    for( var property in object ) {
    try {
    if( !this.prototype[ property ] && object.hasOwnProperty( property ) )
    this.prototype[ property ] = object[ property ];
    } catch( e ) {}
    }
    }

    Once you’ve relived your code of its for-in loop additiction, you’re free to extend the base JavaScript classes with abandon. Good uses of extending base classes include adding toJSON() methods, string escaping, and missing/additional Array helper methods like indexOf() and forEach().

    A favorite of mine, while not modifying any prototype, overloads a constructor function to give IE a consistent interface for XMLHttpRequest:

    if( !window.XMLHttpRequest ) {
    window.XMLHttpRequest = function() {
    var types = [
    "Microsoft.XMLHTTP",
    "MSXML2.XMLHTTP.5.0",
    "MSXML2.XMLHTTP.4.0",
    "MSXML2.XMLHTTP.3.0",
    "MSXML2.XMLHTTP"
    ];

    for( var i = 0; i

  18. Randy Reddig Says:
    July 23rd, 2005 at 03:48

    Missing snippet, with < escaped:

    if( !window.XMLHttpRequest ) {
    window.XMLHttpRequest = function() {
    var types = [
    "Microsoft.XMLHTTP",
    "MSXML2.XMLHTTP.5.0",
    "MSXML2.XMLHTTP.4.0",
    "MSXML2.XMLHTTP.3.0",
    "MSXML2.XMLHTTP"
    ];

    for( var i = 0; i < types.length; i++ ) {
    try {
    return new ActiveXObject( types[ i ] );
    } catch( e ) {}
    }

    return undefined;
    }
    }

  19. Igor E. Poteryaev Says:
    July 23rd, 2005 at 08:45

    Randy,

    It is not hard to implement Object.prototype.extend as function,
    not as method.

    var extend = function (object, extender) {

    var props = extender || {}; // fail-safe
    for (var property in props) {
    object.prototype[property] = props[property];
    }
    return object;
    };

    IMHO, cleaner, cross-browser and a lot less intrusive than adding method to Object.prototype.

  20. Erik Arvidsson Says:
    July 23rd, 2005 at 12:18

    Randy: I think you missed the point. The point is that it is bad to do this because the rest of your project takes such a huge complexity hit.

    If your application needs common functionality across classes/objects then extend your own base class instead of messing with Object.

  21. Randy Reddig Says:
    July 24th, 2005 at 08:33

    No, I just disagree.

    The only “huge complexity” is the addition of a hasOwnProperty() check in a for-in loop, which can be implemented in Safari as I demonstrated.

  22. Erik Arvidsson Says:
    July 24th, 2005 at 23:25

    … and every time you use the in operator.

    I just don’t see the gain in messing with Object.prototype.

  23. Randy Reddig Says:
    July 25th, 2005 at 21:05

    The in operator functions the same on Array objects, so for-in on an array returns 0 through N-1 for arrays of length N.

    The JavaScript 1.5 methods in Array.prototype you’ve implemented will exhibit the same behavior as modifying Object.prototype, “breaking” the in operator.

    Using the in operator as a test for existence of a hash key is dubious as well, for reasons you described above. JavaScript objects may have properties of hash tables, but they are /not/ hash tables.

    Hence the hasOwnProperty() method.

  24. Erik Arvidsson Says:
    July 25th, 2005 at 21:28

    But using the in operator on arrays is incorrect anyway. It is a very common mistake even among more experienced programmers:

    var a = [];
    a[3] = 3;
    for (var i in a) {
    alert(i)
    }

    The length above is 4 but you don’t get 0, 1 or 2. The above code is semantically the same as this:

    var a = {};
    a[3] = 3;
    for (var i in a) {
    alert(i)
    }

    I agree with you regarding the hasOwnProperty method. To make a robust hash table you would need to prefix the field name or use hasOwnProperty. I didn’t want to post this here but here is one simple implementation:

    function HashTable() {
    this._hash = {}
    }

    HashTable.prototype.add = function (key, val) {
    this._hash[key] = val;
    };

    HashTable.prototype.remove = function (key) {
    delete this._hash[key];
    };

    HashTable.prototype.getItem = function (key) {
    if (this._hash.hasOwnProperty(key)) {
    return this._hash[key];
    }
    return undefined;
    };

    HashTable.prototype.containsKey = function (key) {
    return this._hash.hasOwnProperty(key);
    };

    HashTable.prototype.getKeys = function () {
    var res = [];
    for (var k in this._hash) {
    if (this._hash.hasOwnProperty(k)) {
    res.push(k);
    }
    }
    return res;
    };

    HashTable.prototype.getValues = function () {
    var res = [];
    for (var k in this._hash) {
    if (this._hash.hasOwnProperty(k)) {
    res.push(this._hash[k]);
    }
    }
    return res;
    };

  25. Panasonic Youth » Blog Archive » Prototype and extending javascript’s Object or Array Says:
    December 30th, 2005 at 11:23

    [...] 217;t use the Prototype library, as extending Object or Array’s builtin prototype is bad. However, Sam heard the complaints about how Prototype 1.3.1 was breaking existing code [...]

  26. OpenLaszlo Project Blog » Class-based OOP in Javascript done right Says:
    February 19th, 2006 at 11:40

    [...] 17;s really not nice to modify the built-in Javascript classes. One might even claim that Object.prototype is verboten. So I spent a little time re-working what I posted, and now I ha [...]

  27. OpenLaszlo Project Blog » Class-based OOP in Javascript done right Says:
    February 19th, 2006 at 12:26

    [...] it’s really not nice to modify the built-in Javascript classes. One might even claim that Object.prototype is verboten. So I spent a little time re-working what I posted, and now I ha [...]

  28. OpenLaszlo Project Blog » Class-based OOP in Javascript done right Says:
    February 19th, 2006 at 12:52

    [...] it’s really not nice to modify the built-in Javascript classes. One might even claim that Object.prototype is verboten. So I spent a little time re-working what I posted, and now I ha [...]

  29. Mike 18 Says:
    February 20th, 2006 at 17:15

    What does the “unassigned local network address” error mean?

  30. OpenLaszlo Project Blog » Class-based inheritance in Javascript done right Says:
    February 21st, 2006 at 10:10

    [...] 17;s really not nice to modify the built-in Javascript classes. One might even claim that Object.prototype is verboten. So I spent a little time re-working what I posted, and now I ha [...]

  31. OpenLaszlo Project Blog » Class-based OOP in Javascript done right Says:
    February 21st, 2006 at 10:19

    [...] 17;s really not nice to modify the built-in Javascript classes. One might even claim that Object.prototype is verboten. So I spent a little time re-working what I posted, and now I ha [...]

  32. Jeremy Says:
    March 6th, 2006 at 17:52

    I don’t use the prototype.js either… not because of these reasons… I just didn’t want to spend the time to learn it, and it has about zero documentation and almost non-existent commenting.

    But to get around the problem looping over these “object hashes/associative arrays” just keep an array to index the keys. You need this if you want to sort your javascript objects anyways.

    So as you are building your objects of say contacts add to an array too…

    var aContacts = new Array();
    var oContacts = new Object();

    build some contact object stuff stuff keying off the ids
    oContacts[id] = whatever.
    aContacts.push(id);

    then

    var key;
    var nLength = aContacts.length;
    for (var i = 0; i

  33. Jeremy Says:
    March 6th, 2006 at 17:54

    shoot retarded, this blog didn’t escape my greater thans in the loop with HTML entities?

    for (var i = 0; i < nLength; i++)
    {
    key = oContacts[i];
    do stuff with oContacts[key];
    }

    this gets around the prototype.js problem and allows for sorting

  34. A Base Class for JavaScript Inheritance Says:
    March 23rd, 2006 at 13:49

    [...] I want to achieve the above without affecting Object.prototype [...]

  35. Ajaxian » Dean Edwards and Another Base.js Says:
    March 24th, 2006 at 17:56

    [...] I want to achieve the above without affecting Object.prototype [...]

  36. Painfully Obvious » Blog Archive » JavaScript “Associative Arrays” Considered Harmful Says:
    May 18th, 2006 at 09:04

    [...] Actually, we’ve been here before: before version 1.4, Prototype added a couple methods onto Object.prototype, meaning that Object couldn’t even be used in the manner I describe, and a bunch of people rightly took Sam Stephenson to task for it. Object.prototype is verboten. Since version 1.4, however, this is no longer an issue, and therefore there is no longer an excuse. [...]

  37. alexander kirk » Blog Archive » Misuse of the Array Object in JavaScript Says:
    May 18th, 2006 at 11:24

    [...] btw: that post lead me to Object.prototype is verboten which explains for me why my for (i in myvar) {} loops never worked correctly. I was using prototype.js version < 1.4 (which messed with Object.prototype). [...]

  38. Ajaxian » Javascript Associative Arrays considered harmful Says:
    May 19th, 2006 at 06:25

    [...] The other problem with using Arrays as associative arrays means you can no longer extend Array.prototype, which is what Prototype 1.5 does to great effect. Prototype did break Object associative arrays in 1.4 with additions to Object.prototype, something that is fixed in 1.5 after much wailing and gnashing of teeth. Some might argue extending any of the built-in objects’ prototypes is bad form, but those people are wrong. [...]

  39. Twologic » Blog Archive » Ruby OO Continued… Says:
    June 17th, 2006 at 20:59

    [...] I want to achieve the above without affecting Object.prototype [...]

  40. Thomas Frank Says:
    July 13th, 2006 at 06:11

    Object.prototype is erlaubt

    So you say that extending the JavaScript Object.prototype is verboten… Now, this does not go well with my lazy attitude to programming. But neither does the extra checks needed in your for-in-loops if you extend it. Here’s my lazy solution.

    www.thomasfrank.se/object_prototype_is_erlaubt.html

  41. Dean Edwards: Object.prototype is erlaubt Says:
    July 29th, 2006 at 07:22

    [...] Of course, extending Object.prototype is still verboten. Just thought it was interesting. [...]

  42. Matt Warden Says:
    July 29th, 2006 at 11:23

    You have people using Object as a hashtable instead of implementing their own data structure like they should, and you believe the solution is to forbid extending Object.prototype? Nonsense. The solution is to implement the data structure. That’s the solution irregardless of problems introduced by Object.prototype modification.

  43. Thomas Frank Says:
    August 4th, 2006 at 06:29

    @Dean: Glad you like my headline so much that you chose to reuse it: www.thomasfrank.se/object_prototype_is_erlaubt.html

    And that you give yet another example that shows that it is not a problem to extend the Object.prototype.

  44. Erik Arvidsson Says:
    August 8th, 2006 at 08:50

    Thomas: If you want to give up ease of programming (for what???) go ahead. Personally I feel that there are lots of good user cases for using plain Object as a simple hash (you have to have full control of the keys but that is very common).

  45. Goswinus Odekerke Says:
    October 9th, 2006 at 05:49

    I absolutely agree with the statement. I’d like to take it a step further: It’s also verboten to pass an object to a function! Why? Checkout following code:

    function someFunction(o)
    {
    o.e = function() { return “E”; };
    }

    var obj = {a: “A”, b: “B”, c: “C”, d: “D”};

    someFunction(obj);

    for (var key in obj) {
    doSomething(key, obj[key], obj);
    }

    The impertinent function “someFunction” added a function “e” to the newly created object, which will show in the “for .. in” loop!

    I hope you appreciate my sarcasm.

    Just because your application doesn’t require this functionality and/or doesn’t take it in account, doesn’t mean that someone else can’t come up with a valid reason to use it.
    The very fact that Object.prototype is exposed and may be changed, illustrates the power of the language and, more importantly, invites to use it to the max! It also implies that any application should always be aware of this feature and take in account that it has been used!
    If your application fails because of this feature, it says something about your application, and not about the feature.

  46. Michael Says:
    October 10th, 2006 at 04:44

    I have to agree that it is a Bad Thing to modify Object.prototype behind a program’s back. Which is a very different matter than the one Goswinus Odekerke lays out, where an object is passed to a function whose purpose is to modify that object in-place. You /can/ seriously make the case that functions should never modify their arguments in-place, but that is different than saying a library should never silently change the base class of every object in every other script and library in-place.

    However, I have to add that the reason this is bad is because of how people use the “for (p in o)” functionality. Objects have properties, but that doesn’t make them Hash Tables. Okay, sure, they can be used like Hash Tables, but *that* is when you get into trouble: that is, the assumption that Object will only ever have members that you yourself added to it. Enumerating over an object’s members is useful for introspection, but can’t (as we’ve seen) be relied on for clean data storage. Instead, if you actually need a Hash Table, you should be using a Hash Table object, with accessors to return the data items inside (like Erik’s example).

    Unfortunately the de facto coding practice is broken, with people abusing their generic Objects to do the work of specific Hash Tables. The conclusion being that, if you want to play nicely with all those coders, you shouldn’t modify their Object.prototypes.

  47. httpete Says:
    October 30th, 2006 at 11:19

    Here is how to do this in prototypejs fashion.

    Object.extend(String.prototype, {

    trim: function(){
    return this.replace(/^\s+|\s+$/g, ”);
    }
    });

  48. Crisp’s blog » Blog Archive » .toJSONString() and Object.prototype Says:
    December 3rd, 2006 at 16:20

    [...] Some time ago I had a email discussion with Douglas Crockford about .toJSONString() in the JSON JavaScript implementation. Mainly because I wrote a function-based implementation that doesn’t require prototyping Object (that some people consider verboten). [...]

  49. Ruth Martinez Says:
    December 5th, 2006 at 15:04

    Donald Evans…

    The 8745 Michelle Perez blog…

  50. Anthony Adams Says:
    December 5th, 2006 at 16:04

    Helen Thompson…

    The 8366 Sandra Roberts blog…

  51. wioota.com » Blog Archive » Javascript: The Quickening Says:
    January 21st, 2007 at 05:45

    [...] With exploration of Prototype (and Javascript in general) we also learned. We learned that messing with the Object.prototype is verboten and that there were better ways to include functionality than inlining everything. Ben Nolan’s Behaviour library demonstrated this best (well then, anyways, these days I now just include separate files which use the various selector functions in combination with the cross-browser Event Handler implementations found in each major library). [...]

  52. Neil Grover Says:
    February 23rd, 2007 at 21:08

    I don’t get how someone can make such an authoritative claim that I can’t do something in a programming language when the language allows for it… you’re just asking for trouble if you think people will listen and then you continue to blindly use “for in” loops and hope that other peoples code won’t break yours because they’ve done something the language will allow…. wrong on so many levels. For one, an Object is not a Hash, so if you want a hash object then create one.. second, the problem doesn’t lie with Object.prototype, the problem is the assumption people have that a “for in” loop will iterate over their own user properties. Instead of crippling Javascript so you can continue to use “for in” loops over pseudo-Hash tables does not make any sense… I’d sooner not use “for in” loops and extend Object.prototype to have iterator-like capability (for example an “each” function). A possible solution (off the top) might look like:

    Object.prototype.each = function(func, args) {
    for (property in this) {
    if (!(typeof(this))[property]) {
    func(property, this[property], args);
    }
    }
    };

    now just do this instead of “for in” loops:

    var x = {a:’a', b:’b', c:’c'};
    x.each(function(property, value)) {
    alert(‘property name ‘+property+’, value: ‘+value);
    });

  53. Neil Grover Says:
    February 23rd, 2007 at 21:14

    couple typos above but I just tried it out and it works. you can probably copy/paste this into a file and try if you like:

    Object.prototype.each = function(func, args) {
    for (property in this) {
    if (!(typeof(this))[property]) {
    func(property, this[property], args);
    }
    }
    };

    var x = {a:”a”, b:”b”, c:”c”};
    x.each(function(property, value) {
    alert(‘property name ‘+property+’, value: ‘+value);
    });

  54. John Resig - Native JSON Support is Required Says:
    March 6th, 2007 at 15:34

    [...] this point, its pretty safe to say that that extending Object.prototype is considered harmful – and many users agree. Extending an Object’s prototype is generally considered reasonable for [...]

  55. Quotes » Blog Archive » Extending prototypes of built-in objects Says:
    March 8th, 2007 at 03:01

    [...] Considered Harmful (Andrew Dupont), Misuse of the Array Object in JavaScript (Alexander Kirk) and Object.prototype is verboten (Erik [...]

  56. Alwin Blok Says:
    March 9th, 2007 at 13:21

    Question: What is the desired behaviour of for .. in ?

    As Javascript is prototype based, it uses differential inheritance. So the question is, how far should (for .. in) look up into the prototype chain ??
    My guess is: not at all ?

    Ok…, these are not my last words on this issue, but for now, I suggest the following solution.

    Map = Object;
    Object = function(){};

    And you’re done.
    new Map() does not inherit from Object.prototype. new Object() does.
    Objects (Maps!) created with {}-literals do not inherit from Object.prototype.

    … At least, in Safari, IE and Opera.
    Unfortunately, Frefox interprets {} as new Object(). and thus {} does inherit from Object.prototype.
    Maybe someone can f

gipoco.com is neither affiliated with the authors of this page nor responsible for its contents. This is a safe-cache copy of the original web site.