Tuesday, July 19, 2011

Function.prototype vs Object.prototype

If we want to define an extension method available for each and every object in the global scope we can do this in different ways, for example like this:

Function.prototype.someMethod = function () {
    return 'Hello from Function';
}
Or like this:
Object.prototype.someMethod = function () {
    return 'Hello from Object';
}
So what is the difference?
In the first case it will work for functions only:
var someFunction = function () {
};
var hello = someFunction.someMethod();
//someMethod is Ok. hello equals to 'Hello from Function'

At the same time someMethod will give us an “undefined” error if we try to call it from an object:
var someObject = {};
var hello = someObject.someMethod();
 //someMethod is undefined

On the other hand, if we modify the prototype of Object type, then it will work for both functions (including constructor based objects) and objects.
Object.prototype.someMethod = function () {
    return 'Hello from Object';
}

var someObject = {};
var hello = someObject.someMethod();
//someMethod is Ok. hello equals to 'Hello from Object'

var someFunction = function () {
};
hello = someFunction.someMethod();
//someMethod is Ok. hello equals to 'Hello from Object'

What will happen if we modify prototypes for both Function and Object types at the same time?

Object.prototype.someMethod = function () {
    return 'Hello from Object';
}

Function.prototype.someMethod = function () {
    return 'Hello from Function';
}

The result will be different for functions and objects. Each of them will use it’s own overload:

var someFunction = function () {
};
var hello = someFunction.someMethod();
//someMethod is Ok. hello equals to 'Hello from Function'

var someObject = {};
var hello = someObject.someMethod(); 
//someMethod is Ok. hello equals to 'Hello from Object'

This is fair enough. Modification of Function’s prototype overwrites Object’s one because Function is based on Object’s prototype.
And if we go further and delete someMethod from Function the Object’s implementation will shine through:
delete Function.prototype.someMethod;
hello = someFunction.someMethod();
//someMethod is Ok. hello equals to 'Hello from Object'

I was a little bit confused at this point, but writing these samples helped me to understand where I was wrong in my assumptions.
So maybe it will help to someone else as well :).

1 comment:

Deja said...

Правильно так:
delete Function.prototype.__proto__.someMethod

но __proto__ не поддерживается в IE, т.к. это свойство вне стандарта.
Оно в стандарте отмечено как [[prototype]] и является внутренним, не доступным для программиста.