Prototyping Object in Javascript breaks jQuery?
You should never extend Object.prototype
. It does far more than break jQuery; it completely breaks the "object-as-hashtables" feature of Javascript. Don't do it.
You can ask John Resig, and he'll tell you the same thing.
Object Prototype Function Breaking in jQuery
By passing a value
to the descriptor, you've just overwritten the method with that empty function (which is the one doing nothing and returning undefined
). If you really want to define a method on Object.prototype
(which you absolutely should not do), you'd need to use
Object.defineProperty(Object.prototype, 'multiparter', {
value: function(route) {
return route.reduce(function(newObj, key) {
return newObj[key]
}, this);
},
enumerable: false,
configurable: true
});
object.prototype breaking javascript
Extending built-in prototypes is bad practice. It can break scripts that expect that doesn't happen, such as jQuery.
There is no reason for you to do this. Create a normal function instead:
function getKey(obj, value) {
// ...
}
and use getKey(playlistids, playing)
instead of playlistids.getKey(playing)
. Why does this JavaScript prototype function break jQuery?
Because this is going to add an enumerable item to every single object. Sizzle (which jQuery uses) uses object literals to configure their selector parsing. When it loops these config objects to get all tokens, it doesn't expect your function. In this case, it's probably trying to use your function as a RegExp
.
Imagine this scenario:
var obj = { a: 1, b: 2, c: 3 };
var result = 0;
for (var prop in obj) {
// On one of these iterations, `prop` will be "allKeys".
// In this case, `obj[prop]` will be a function instead of a number.
result += obj[prop] * 2;
}
console.log(result);
If you have added anything to Object
's prototype that can't be used as a number, you will get NaN
for your result.A good solution to this problem is to add the allKeys
function to Object
instead of Object.prototype
. This mimics Object.keys
:
Object.allKeys = function (obj) {
var keys = [];
for (var key in obj)
{
// Very important to check for dictionary.hasOwnProperty(key)
// otherwise you may end up with methods from the prototype chain..
if (obj.hasOwnProperty(key))
{
keys.push(key);
//alert(key);
} // End if (dict.hasOwnProperty(key))
} // Next key
keys.sort();
return keys;
}; // End Extension Function allKeys
jQuery conflict with native prototype
You can avoid these problems by making your extensions to the native prototypes as non-enumerable:
Object.defineProperty(Object.prototype, 'myVeryGreatFunction',{
value : function() {},
enumerable : false
});
Object.defineProperty
documentation on MDNAs Jan Dvorak mentioned, this solution does not work for old browsers (IE8-).
jQuery error when extending object prototype
In this report they say they don't want to fix that. So don't use Object.prototype when working with jquery.
Assigning Object.prototype causes issues with jQuery
Don't monkey patch Object.prototype
.
Object.prototype.replace = "lol";
for (var i in { "bar": 42 }) {
alert(i);
}
// "bar"
// "replace" :(
Basically for ... in
loops iterate over all properties in an object including ones defined on the prototype. This is why it's really bad practice to extend or change Object.prototype
.Some people also go as far as "Don't monkey patch Array
, String
, Function
, ...".
You should never mess with the Object.prototype
. The rest of the native prototypes are a style choice.
Define your function on Object
.
Object.replace = function() { ... };
var o = Object.replace(p);
ES5:With ecmascript 5 you can set properties as non-enumerable
Object.defineProperty(Object.prototype, "replace", {
value: function() { }
});
I tried to prototype a length() method to Object and broke jQuery – how?
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.
Alternative methods for extending object.prototype when using jQuery
By not including the descriptor in Object.defineProperty(obj, prop, descriptor)
JavaScript defaults all the Boolean descriptor attributes to false. Namely writable
, enumerable
, and configurable
. Your new property is hidden from the for in
iterators because your _init
property is enumerable:false
.
I am not a fan of JQuery so will not comment on why in regard to JQuery
There is no absolute rule to adding properties to JavaScript's basic type and will depend on the environment that your code is running. Adding to the basic type will add it to the global namespace. If your application is sharing the namespace with 3rd party scripts you can potentially get conflicts, causing your code or the third party code or both to fail.
If you are the only code then conflicts will not be an issues, but adding to object.prototype will incur an addition overhead on all code that uses object.
I would strongly suggest that you re examine the need for a global _init. Surely you don't use it every time you need a new object. I am a fan of the add hock approach to JavaScript data structures and try to keep away from the formal OOP paradigms
JS Object this.method() breaks via jQuery
The identity of this
is a common problem in javascript. It would also break if you tried to create a shortcut to doSomething
:
var do = Bob.doSomething;
do(); // this is no longer pointing to Bob!
It's good practice to not rely on the identity of this
. You can do that in a variety of ways, but the easiest is to explicitly reference Bob
instead of this
inside of doSomething
. Another is to use a constructor function (but then you lose the cool object-literal syntax):var createBob = function() {
var that = {};
that.Stuff = '';
that.init = function() {
that.Stuff = arguments[0];
};
that.doSomething = function() {
console.log( that.Stuff );
};
return that;
}
var bob = createBob();
Related Topics
How to Export Excel Files Using JavaScript
Google Map API - Multiple Icons in Wrong Spot
How to Read the Correct Time/Duration Values from Google Spreadsheet
In JavaScript, Can You Extend the Dom
How to Use Getelementsbyclassname in JavaScript-Function
Intercept Paste Event in JavaScript
How to Execute a Dynamically Loaded JavaScript Block
JavaScript Ternary Operator Example with Functions
If (Key in Object) or If(Object.Hasownproperty(Key)
Keep Bootstrap Dropdown Open When Clicked Off
How to Trigger Click on Page Load
React Doesn't Reload Component Data on Route Param Change or Query Change
Gmail Extension, Sendmessage to Background from Page Context
How to Write Regex to Validate Dates
Using Fetch API to Access JSON