4

I wrote the following:

Object.prototype.length = function(){
    var count = -1;
    for(var i in this) count++;
    return count;
}

It works. But when I execute my page, even without using this function, Firebug tells me that jQuery's .appendTo() is no longer a function. Why would this be?

Barney
  • 63
  • 1
  • 5

2 Answers2

7

That prototype extension is breaking the $.each method, because this method detects between arrays and objects using the length property (in jQuery 1.4.2):

// core.js Line 533
each: function( object, callback, args ) {
    var name, i = 0,
        length = object.length, // <--- your function from Object.prototype
        isObj = length === undefined || jQuery.isFunction(object);
//...

As you can see, the isObj variable will be true only if it doesn't contains a length property (or the property value is undefined).

If isObj is false, jQuery will try to iterate using a normal for loop:

for ( var value = object[0];
    i < length && callback.call( value, i, value ) !== false; value = object[++i] ) {}

Then, the appendTo method is created using $.each, that's why is not defined:

//...
jQuery.each({
    appendTo: "append",
    prependTo: "prepend",
    insertBefore: "before",
    insertAfter: "after",
    replaceAll: "replaceWith"
},
//...

I will always recommend to stay away from extending Object.prototype, when you extend this prototype ALL objects receive those additional properties.

This is especially problematic since when you iterate over the properties of the object these new properties appear, causing all sorts of unexpected behavior.

Christian C. Salvadó
  • 807,428
  • 183
  • 922
  • 838
  • Riight. I'm relatively new to Objects so it didn't hit me – the thing I'm doing's self-defeating because I'm contaminating the Objects I'm looking to methodise in the first place. Thanks for stepping through that for me. – Barney Apr 14 '10 at 15:45
  • I understand the issue with extending Object.prototype. But what if I still want to add a property to Object.prototype which is some kind of generic function which I want to make it accessible to all.? How can I make it not appear in the for loop. I see that my method appears in the __proto__ object which has many other functions defined in it but they dont appear as keys in the for loop ? Help me to add a function which is not enumarable – Kpatel1989 May 22 '15 at 08:08
4

It's probably because jQuery's .appendTo depends (indirectly) on Object.length, which is builtin in JavaScript, and isn't a function.
If you really want to add that method to Object, call it something that won't interfere with pre-existing methods; something like objLength or obj_length (or whatever).
You can also do something like this to check if the attribute you want to add to an object already exists for that object (lifted straight from Crockford):

Object.prototype.method = function (name, func) {
    if (!this.prototype[name]){
        this.prototype[name] = func;
        return this;
    }
};

And apply your function like so:

Object.method('myLength', function () {
    var count = -1;
    for (var i in this) {
        count += 1;
    }
    return count;
});

And I know my loop has brackets around a whole one statement, but it improves readability and maintainability. I have heard those are good things.

yarmiganosca
  • 2,215
  • 2
  • 14
  • 9
  • 1
    This is totally off topic, but who told you extra brackets improve readability or maintainability? Readability could be debated but I don't see how it's more maintainable other than purely by virtue of possibly being more readable. I don't buy the argument that the extra braces might be needed in the future. Adding code that might be needed is a horrible practice. I find that concise code is much easier to read. IMO extra {} == more clutter and less code on the page. – jcoffland Nov 19 '12 at 04:58
  • @jcoffland Omitting brackets around statements like `for` is bad practice because it allows for ambiguity of control flow depending on how the code is formatted. The same may be said of ternary operators, lack of indentation, using non-descriptive identifiers, placing everything on a single line, and omitting semicolons where optional. If it was all about brevity over a reasonable standard of cross-developer readability, we'd be using bytecode to script things. Any developer serious about code style will agree: [link](http://addyosmani.com/blog/javascript-style-guides-and-beautifiers/) – Beejor Jan 14 '15 at 23:33
  • @Beejor, I'm very serous about code style and I don't agree. You're saying that if I fail to use extra brackets AND I fail to indent consistently then the code may appear to be ambiguous. With that, I do agree. What I don't agree with is that the solution is to add unnecessary brackets. The correct solution, IMHO, is to indent your code correctly, all of the time, and use white-space judiciously. Then you wont need to add nonsense code. We are verging on a religious war here so I'll leave it at that. – jcoffland Apr 16 '15 at 23:56