Just a small Prototypical Inheritance question
Recently I was trying to create a custom Method jut like e.g: JS’s .toUpperCase() and other methods… that uses the this reference from the prefixed object.
And it works nice (stupid usless example) :
Object.prototype.customMethod = function(){
return this.toLowerCase() ;
};
And can be used like:
// access some object and get a key value
member.name; // JOHN
// use custom Method
member.name.customMethod(); // john
The issue is that seems like the Method .customMethod() inherits globally every Object.
How to make it less intrusive and be referenced to the prefixed object only? or at all?
Here is an example: http://jsbin.com/evaneg/2/edit
// CREATE OBJECT
var obj = { "text" : "Hi" };
// TEST OBJECT KEY VALUE
alert( "OBJECT TEXT: "+ obj.text ); // Hi
// CREATE CUSTOM METHOD ( just like e.g. JS's .toUpperCase() method )
Object.prototype.addText = function(){
return this+' there!';
};
// USE CUSTOM .addText() METHOD
alert( "OBJECT TEXT+method: "+obj.text.addText() ); // Hi there! // wow, the method works!
for(var key in obj){
alert( 'obj KEYS: '+ key ); // text // addText
}
// hmm... addText method as obj Key ???
// ok let's try with a new one...
var foobee = { "foo" : "bee" };
for(var key in foobee){
alert( 'foobee KEYS: '+ key ); // foo // addText
}
// addText ...again... but why?
I read also this http://javascript.crockford.com/prototypal.html and lots of other similar things here on SOverflow but most of them focus on the use of creating a new F( arguments ) that use specific arguments, which is not my case. Thanks for any explanation
You don’t have to add the method to every object — only the kind of object which you are working with. If it is a string method, you can add it to
String.prototypeand have it defined on all strings.Note that this does make methods enumerable, which means they show up in a
for..inloop.Object.defineProperty
If you can only care about supporting browsers since 2010 (no IE8), then I highly recommend using
Object.definePropertyto define properties so that they won’t be enumerable:The code above logs the “foo” property and the “methodA” property but it doesn’t log the “methodB” property because we defined it as non-enumerable. You’ll also notice built-in methods like “toString”, “valueOf”, “hasOwnProperty”, etc also don’t show up. This is because they are also defined as non-enumerable.
This way other scripts will be allowed to use
for..infreely and everything should work as expected.Going back to specific built-ins
We can define non-enumerable methods on specific types of objects with
Object.definePropertyas well. For instance, the following adds acontainsmethod to all arrays which will returntrueif the array contains a value andfalseif it doesn’t:Note that since we defined this method on
Array.prototype, it is only available on arrays. It is not available on other objects. However, in the spirit of other array methods, it is written with enough generality that it can be called on array-like objects:Calling
containsonargumentsworks above, event thoughargumentsisn’t a true array.Simplifying the Boilerplate
Using
Object.definePropertyprovides a lot of power, but it also requires a lot of extra code which most people would rather not type all the time. That was understood when the ECMAScript committee defined the function, but they assumed people could write helper functions to make the code cleaner. Keep this in mind. For example, you can always do something like the following:Then you can do:
There are even some small libraries which have been developed to help with some of this stuff. Check out Andrea Giammarchi’s redefine.js as an example.
Caution
The only real caution here is that if you add your own methods to built-ins, it’s possible to have name clashes with (a) future versions of JavaScript or (b) other scripts. (The name-clash problem is being resolved in the next version of JavaScript with symbols.) Many would argue that this is a big enough problem that you shouldn’t ever modify built-ins but should stick to modifying only the stuff you “own” — things you created with your own constructors. I would tend to agree in some (or many) situations, but I think for your own personal use and learning, playing around with built-in prototypes can be a very helpful and fun thing to do.
Check out this article on weighing some of the costs of modifying built-ins for a more detailed description of possible drawbacks: http://perfectionkills.com/extending-built-in-native-objects-evil-or-not/ Note that this article is a little dated (1 1/2 years) and one of his major complaints is the enumerability thing, which is possible to overcome with
Object.definePropertyin all modern browsers. As I said, the other major problem (name-clashes) will be solved in the next version of JavaScript. Things are getting better!