9
Object.prototype.doSomething = function(p) {
    this.innerHTML = "<em>bar</em>";
    this.style.color = "#f00";
    alert(p);
};

document.getElementById("foo").doSomething("Hello World");

<div id="foo"><strong>foo</strong></div>

The code above works fine.

But I remember that I saw this somewhere: Do not mess with native Object. well, something like that.

So is it ok to define a prototype function on Object? Are there any reasons that I should not do this?

user1643156
  • 4,407
  • 10
  • 36
  • 59
  • Is this for a library others will be consuming? Or for your own application code? – Roatin Marth Mar 25 '13 at 17:07
  • I'm writing a small library that others may be using as well. As the answers suggested below, I think that I should not be doing this, no matter who the code is written for. – user1643156 Mar 25 '13 at 17:17

4 Answers4

8

The only safe way to add to Object.prototype is to use the ES5 method Object.defineProperty to create a non-enumerable property:

Object.defineProperty(Object.prototype, 'doSomething', {
    value: function(p) { ... },
    enumerable: false,  // actually the default
});

This ensures that the new property doesn't appear if you do for (key in object).

Note that this function cannot be reliably shimmed because non-enumerable properties didn't exist in previous versions of ECMAScript / JavaScript.

In any event, if your method only applies to HTML page elements, you would be better adding this to Element.prototype instead of to Object.prototype, although older (IE) browsers may complain if you do this.

Alnitak
  • 334,560
  • 70
  • 407
  • 495
  • Isn't [`hasOwnProperty`](https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/hasOwnProperty) a best practice now anyway though? – Roatin Marth Mar 25 '13 at 17:06
  • 1
    @RoatinMarth no, IMHO `hasOwnProperty` is _old_ best practise. In an ES5 browser it should be unnecessary. Any code that uncleanly messes with `Object.prototype` should be banished. Even jQuery omits the `hasOwnProperty` test and explicitly states that it'll fail if you use code that abuses it. – Alnitak Mar 25 '13 at 17:07
  • `non-enumerable properties don't exist in previous versions of Javascript.` which version do you mean by `previous`? – user1643156 Mar 25 '13 at 17:21
  • @user1643156 anything prior to ECMAScript 5.0 – Alnitak Mar 25 '13 at 17:22
  • 1
    IE 6/7/8 supports only ECMAScript 3.0 (JavaScript 1.5). so I guess `Object.defineProperty` is not a cross-browser option for my problem. – user1643156 Mar 25 '13 at 17:30
  • @user1643156 no, not if you're stuck with supporting browsers that old. Adding to `Element.prototype` might work in IE7/8 (but probably not IE6). – Alnitak Mar 25 '13 at 17:36
1

Generally not a good idea. That function is now available on everything in your app that uses the Object prototype(which is a lot) and will show up in functions that enumerate the Object proto.

A better option is to define a separate prototype:

function MyObject {
    ...
}

MyObject.prototype.doSomething = function() {
    ...
}

var myObj = new MyObject();
Ryan O'Neill
  • 1,710
  • 2
  • 13
  • 24
1

If you add stuff to the object prototype, you lose the nice object iteration functionality using for p in obj, since enumerable properties you have added are iterated over as well on all objects.

For example:

Object.prototype.doSomething = function(p) {
    this.innerHTML = "<em>bar</em>";
    this.style.color = "#f00";
    alert(p);
};

for (p in {foo:"bar"}){
    console.log(p);
}

//foo
//doSomething

Unexpectedly, you will also get doSomething logged. To fix this, you will have to add a hasOwnproperty check when iterating over your object, but the risk here is that you could break other code that doesn't expect a plain object to have properties other than the ones specified in the literal.

Asad Saeeduddin
  • 46,193
  • 6
  • 90
  • 139
0

Another option is to call a method, defined not as an object prototype method-

function doSomething(p) {
    this.innerHTML = "<em>"+p+"</em>";
    this.style.color = "#f00";
    alert(p);
};

//

doSomething.call(document.getElementById("foo"),"Hello World");
kennebec
  • 102,654
  • 32
  • 106
  • 127