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 Arrays. 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 prototypes, 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