Prototype keyword in Javascript
"Prototype" is something that plays a role in objects.
In Javascript, everything is an object. Every object has a kind, and thus inherits the prototype
of that kind.
For example, take a simple array: var a = []
. You can make operations with it, like a.push(10)
. Where does this push
method come from? From the prototype of Array
object, which a
is.
You can add your own methods to Array
objects just by defining them in the prototype
object. For example:
Array.prototype.sortNum = function() {this.sort(function(a, b) {return a - b});};
This way you can do something like a.sortNum()
with all arrays, even the ones created before you defined the sortNum
method.
(Note: for compatibility reasons, it's usually not recommended to extend the prototype of native objects like Array
s. But this particular example is usually a welcome addition, as well as normalizing methods like map
and forEach
for older browsers.)
(Just never ever extend Object.prototype
! Unless you don't care to mess up for...in
statements, the in
operator and these sort of cases.)
If you want to define your own classes, like the name MyConstructor
suggests, you'll have to define its prototype
to define the methods for all the instances of that class:
function MyConstructor(name) {this.name = name};
MyConstructor.prototype = {
print: function() {return this.name;}
};
var mc = new MyConstructor("foo");
alert(mc.print()); // alerts "foo"
You can define more than just functions in prototype
s, too:
MyConstructor.prototype.age = 30;
alert(mc.age); // alerts 30
Watch out when you do this to define "default" object values, because changing it may cause a change in all instances of that class.
But this comes handy with Object.defineProperty
:
Object.defineProperty(MyConstructor.prototype, "wholeString", {
get: function() {return this.name + "=" + this.age;},
set: function(v) {this.name = v.substring(3);}
});
alert(mc.wholeString); // alerts "foo = 30"
(Unfortunately, IE<9 allows this only for DOM objects...)
When you define MyConstructor.age = 30
instead, what you're actually doing is defining a member of the function MyConstructor
, so mc.age
would be undefined. Every instance of MyConstructor
inherits the methods and members defined in MyConstructor.prototype
, not the ones of the function MyConstructor
.
There's much more to say, actually. Objects can be of a subclass of another class, thus inheriting the prototype
of the superclass, too. For example, document.body
is an instance of HTMLBodyElement
, which is a subclass of HTMLElement
, which is a subclass of Element
and so on, until you get Object
as the upmost superclass. So, document.body
inherits all the methods defined in the prototype of HTMLBodyElement
, HTMLElement
, Element
and Object
. This is called the prototype chain.
Doing the same with custom objects is a bit tricky:
function Class() {};
Class.prototype.foo = function() {alert("foo");};
function Subclass() {};
Subclass.prototype = new Class();
Subclass.prototype.bar = function() {alert("bar");};
var a = new Class(), b = new Subclass();
a.foo(); // alerts"foo"
a.bar(); // throws an error
b.foo(); // alerts "foo"
b.bar(); // alerts "bar"
a instanceof Class; // true
a instanceof Subclass; // false
b instanceof Class; // true
b instanceof Subclass; // true
In JavaScript, function objects have a built-in .prototype
property. The value of this property is an object. If the function is used as a constructor, the resulting instances inherit from that "prototype" object.
Example:
var Dog = function () {}; // the constructor function
Dog.prototype.bark = function () {}; // adding a method to Dog.prototype
var dog1 = new Dog; // creating a new instance
dog1.bark(); // the instance inherits the "bark" method from Dog.prototype
Note that the .prototype
property (of function objects) is not the same as the [[Prototype]]
internal property. All objects contain the latter. It's an internal reference to an object's prototype. (In the above example, the dog1
object's [[Prototype]]
refers to Dog.prototype
.) On the other hand, only function objects have a built-in .prototype
property (which makes sense since only function objects can be used as constructors).
var foo = function () {};
foo.bar = 5;
foo.prototype.foobar = 10;
var x = new foo();
x.bar; // undefined
x.foobar; // 10
Edit: Also, you can then do
foo.prototype.foobar = 20;
x.foobar; // 20