Object.prototype is verboten 98

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).

  • Pingback: wioota.com » Blog Archive » Javascript: The Quickening

  • Neil Grover

    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);
    });

  • Neil Grover

    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);
    });

  • Pingback: John Resig - Native JSON Support is Required

  • Pingback: Quotes » Blog Archive » Extending prototypes of built-in objects

  • http://www.alwinblok.nl Alwin Blok

    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 fix this. It is open source..

    It pretty much solves the problem, except for the use of new `Object()` statements in Firefox. You’ll have to use an `Object.create()` method.
    Or one can use `new Object(null)` to create an object and `new Object()` to create a Map with the following:

    // for firefox – hack
    Object.prototype.testff = ‘testff’
    for(var a in {}){
    Object = function(){
    if(arguments.length == 0)
    return this.__proto__ = null
    }
    break;
    }
    delete Object.prototype.testff

  • Pingback: Dean Edwards: Rules For JavaScript Library Authors

  • Pingback: Bobtown » Blog Archive » Javascript Bibliotheken: Mono- oder Mischkultur?

  • HeroreV

    With JavaScript 1.7 you can define an iterator for objects that only iterates over the local properties. That way you can load up Object.prototype to your heart’s content.

  • http://dhtmlkitchen.com/ Garrett

    I have been many times grateful for this post as a reference point.

  • Cecil Ward

    [Off topic.]
    @Randy: I should just add that the code above, posted a long time ago, which carries out a search for the ‘latest’ version of MSXML should be amended to read as as follows
    ..
    “MSXML2.XMLHTTP.6.0″,
    “MSXML2.XMLHTTP.3.0″,
    ..
    rather than checking for versions 5.0 or 4.0. Versions 5.0 and 4.0 are now deprecated, MSXML6 is the current recommended version, and MSXML3 as the recommended fallback.

    See article “Using the right version of MSXML in Internet Explorer” at the Microsoft XML Team blog on blogs.msdn.com.

  • http://www.coolpositive.blogspot.com coolpositive

    Here is how to do this in prototypejs fashion.

    Object.extend(String.prototype, {

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

  • http://www.coolpositive.blogspot.com coolpositive

    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);
    });

  • Mike Amy

    // How about this simple solution: ban the b**tards from fiddling with your {}!
    // running this bit of code before anything else pulls the carpet from under their feet:

    var BaseObject = Object;
    Object = function () { return new BaseObject(); }

    // what this does is separate the {} prototype from the Object prototype.
    // However calling new Object() returns what you’d expect.

    Object.prototype.x = 5;

    var a = {a:1,b:2,c:3};
    var s = ”;
    for (i in a)
    s+=a[i];

    // s is now ’123′, not ’1235′
    // I know there are other problems with this eg:

    [] instanceof Object == false; // it used to be true.

    // Can anyone suggest how can we deal with this?
    // Mike Amy

  • Mike Amy

    OK, I missed post number 56, and only tested my example in Safari 3.0.4 and 2.0.4.

    But as far as I can see from post 56, unless any third party script you then include uses the unusual ({}).prototype.property = …

    instead of the far more common

    Object.prototype.property = …

    to override the base class, it should still work. You basically make the root class {}.
    Still the problems of inheritance testing remain (even though testing for inheritance from Object seems strange as it should always be true)

  • http://isthisjersey.com Mike Amy

    // I tried out some stuff with Firefox. If you do this:

    Hash = Object;
    Object = function () {return new Hash();}

    /* And assuming Hash.prototype doesn’t change, then:
    - Hash becomes something like the root of the heirarchy.
    - {} and Object() return hashes (obviously). The prototype will be empty and this cannot be overridden.
    - setting Object.prototype has no effect on new Objects or {}-literal objects.

    To solve the instanceof problem:

    For base classes, eg Array, if you do:
    */

    Function.prototype.extends = function (func) {
    this.prototype.__proto__ = func.prototype;
    return this;
    }
    Array.extends(Object);

    /* then instanceof works again:

    i.e. [] instanceof Object == true;

    You’d have to do this for the other ‘classes’ too, otherwise they will use the vanilla prototypes.

    In addition to getting instanceof to work, overriding the Object.prototype WILL now affect arrays. So you can introduce new methods near the top of the ‘class’ hierarchy as well as iterating easily over Objects with for (i in obj) {…}. Best of both worlds.

    I tested this in Firefox (Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8.1.1) Gecko/20061204 Firefox/2.0.0.1) with Venkman version 0.9.87.2.
    I also tested it in Safari 3.0.4. , but not in IE.

    Lastly, if you want your own new base ‘class’ to start your own hierarchy, i.e. start with a blank slate, it couldn’t be easier, you do nothing special:

    function MyObject() {};

    Voila.

    */

  • http://isthisjersey.com Mike Amy

    sorry, ‘extends’ method should have been ‘extend’

  • Pingback: Crossed Browser » Blog Archive » Rapid Client Side Development of UI Components with Base

  • Ricardo

    @Mike: doesn’t work for me in FF 2.0.0.14, the “Hashes” still inherit from Object, as do Array/Date/etc.

  • Pingback: Multiple String Replacement Sugar

  • Pingback: Crossed Browser » Blog Archive » JavaScript Presentation Notes

  • Pingback: Defining classes and inheritance in JavaScript - Global Point Forum

  • Pingback: Evan Hanson | Prototype JS in Unison with the Javascript Prototype Model

  • Pingback: [翻译] 写给JavaScript库开发者们的规则 - 岁月如歌

  • Pingback: 卢子嘉的BLOG » 写给JavaScript库开发者们的规则

  • Pingback: Borgar.net » Safe fun with Object.prototype.

  • tantan

    I think it is very important. And other rule I think it is also important is that do not expand any native object,such as String or Function. Because in some projects, you do not know controls you buy or use,specially the project many teams program together, whether expand these native object,it causes very dangerous result.

  • Mosh Jahan

    This is so funny. What you (Erik) are suggesting is akin to telling a sports car driver to drive slow because driving fast is dangerous. The driver should be capable of deciding how to operate the car within safe limits by employing checks. I agree with all the posters that recommend adding checks to code and allowing people to utilize Object.protoype. With modern compute power the performance overhead for additional checks is miniscule and not noticeable. As for readability of code I’m all for it, but sometimes small sacrifices have to be made.

  • Pingback: Background

  • Pingback: JS库开发原则 at Jeekundo.com

  • http://alexander-web.com Michael D. Alexander

    I almost can’t believe the patently false information you’re peddling here on your website. I hope you don’t get paid to program for a living–God help us!

    JavaScript is a class-less, prototype based language. So, if you don’t ever alter the default object that the runtime assigns to every function’s prototype property, how are you ever going to leverage inheritance???

    When the runtime sets the prototype property to point to a default (empty) prototype object, it also sets the constructor property to point to the functions definition.

    If you ever reassign the prototype, reassign the constructor property to point to the “constructor” and you won’t “break” your “objects-as-hash-tables” feature. It’s that simple Eric.

  • radom

    Here’s an interesting js object layout diagram:

    http://mollypages.org/misc/js.mp

  • Pingback: onli blogging

  • gnark

    why do all the people always go down on the “for..in” use case? that one just explains what is it all about. the meaning of it is far more than just how to “fix” a certain pattern.

    Object by definition IS a (or behaves like a) map. it represents the very native implementation of a hash map. javascript MEANS everything is built on top of that. finding yourself implementing own maps that utilize filtering or a self-rolled manual lookup algorithm you must have done something wrong.

    its not the other way round that an object must be specialized to represent a map implementation.

    whenever its about scripts on your homepage that do cool things all alone, mess with it. but whenever its about interoperability and composing things together it is just stupid to make yourself incompatible to the rest of the world.

    when i create client app that has a function

    APP.processItem = function(item) {
    if (item.flags.remove) {
    this.removeItem(item);
    return;
    }
    // do other things with item
    }

    and it falsely procs just because someone attached “remove” to the very super-model of all models then i am screwed. the lib or component (that needs to run within my very window scope) that did this to my runtime cannot be used anymore.

    today we need to rely on and confide in 3rd party components. otherwise this whole talking is useless and you can put it into a directive catalogue of your very own closed-source it company.

    just imagine all the config objects, all the json data, that would have to filter out potential polluted objects fields.

    put your “extension” to the prototype object in the chain where you need it and where it makes sense. “remove” function would go to (your) “Element” constructor, not to “Object”.

    parking your car right in the middle of a street, just because technology lets you to do so, is not very smart unless its your private property.

    inheritance itself is done by the prototype chain itself and does not rely on some “extend” method baked into the template of all objects. Object IS {}.

    manipulating the Object.prototype is probably not verboten but it is “obstrusive” and therefore WILL make others and finally your life harder.

  • Marcus Pope

    Erik you are flat out wrong – Object.prototype extensions do not break the “object-as-hash-tables feature in javascript” as you put it, but your lack of understanding about what “for..in” statements do underneath the hood however do lead to problems in your particularly flawed code examples.

    Just to clear up some confusion – this comment thread is full of misinformation and bad advice. Check out my comments near the end of a related thread -

    http://www.thomasfrank.se/object_prototype_is_erlaubt.html

    to find out why.

  • Marcus Pope

    Object.prototype extensions do NOT break for..in or if..in statements in javascript they operate without exception and as expected / designed unless you have incorrect expectations like Erik does. But try it for yourself…

    Object.prototype.test = function() { };

    for (var x in {}) { };

    This code will execute without any errors in javascript – ALWAYS.

    However, if some programmer doesn’t check the data type or hasOwnProperty attribute (or similar approach) of the values they are iterating over and their code breaks because of their bad programming practices then it’s their own fault that a bug in THEIR code broke the intended behaviors of javascript, not that of the person who extended the object prototype.

  • Marcus Pope

    By Erik’s (and so saddly Dean Edward’s) perspective this must be a flaw of the person who wrote the extension or of the Javascript language itself. Because if requiring the use of a hasOwnProperty check on an object iteration is not a legitimate practice, then neither is requiring the check of a variable’s null status before accessing properties of the non-existent data in said variable. And the logical jump of course is to bannish a fundamental and intrinsicly powerful and amazing aspect of the language’s feature set to avoid fixing that bug.

  • Marcus Pope

    Ultimately the bug is in Erik’s code because he didn’t write it like this…

    for (var x in obj) { if (obj.hasOwnProperty(x)) { … }}

    in the same way you’d write this

    function(test) { if (test != null) { for (var x=0; x < test.length; x++) { … }}}

    to prevent test.length throwing an error when test == null;

    (code oddly formed to get through the really buggy <> comment engine.)

  • Pingback: Object#merge – Useful JavaScript Game Extensions 17

  • Pingback: Problemas com Object.prototype no Javascript - Milfont Consulting

  • Pingback: Monkey Patching Javascript | donwills

  • http://js-bits.blogspot.com/ Juan Mendes

    @Marcus Pope: You’re just shifting the blame. You’re saying, everyone should be aware that Object.prototype may be modified and they just need to wrap every single for in loop in their app with a call to hasOwnProperty because I think augmenting Object.prototype is useful. You’re OK with that because, as you said, your app only has 4 of those loops. This article shifts the blame to people who augment Object.prototype.

    I would love to mess with Object.prototype, there are awesome possibilities. However, I am not willing to make for in loops more complicated than they should be. Once we can all set the enumerable flag on properties, then you can augment Object.prototype to your heart’s content.

    I’m not going to convince you, but I can say that I will never use a library that does so and neither will most developers. Prototype agreed with Erik and removed all its Object.prototype extensions.

  • Pingback: JQuery Type Data « RPL Class

  • Pingback: Fixing the JavaScript typeof operator « JavaScript, JavaScript…

  • Pingback: Fixing the JavaScript typeof operator « code elephant

  • Higgs

    I haven’t read all the comments so I don’t know if this has been said already but I think using Object.prototype is great, just make sure your new function isn’t enumerable, that way you you won’t break the “object-as-hash-tables feature” in javascript and you also won’t need to use hasOwnProperty() in every for in loop. I’m not sure if this worked back in 2005, but it does now.

  • Pingback: Extending JavaScript Natives « JavaScript, JavaScript…

  • http://webneurons.com John Middlemas

    This problem is solved in JavaScript 1.8.5 (ECMAScript 5th Edition) as follows:-

    Object.prototype.foo = 1

    Object.defineProperty(Object.prototype, “foo”, {enumerable: false})

    Then foo will not appear in any for(name in obj) loop since it has been set not enumerable.