JavaScript is not a class-based object oriented programming language and thus has no concept of a class, unlike languages like C++ and Java that use classical inheritance. Rather it uses prototypal inheritance - every object inherits from some other object through a concept known as the prototype chain.
Everything is an object
Well, not everything.
Operators like + and % aren’t objects.
A literal such as "Howdy" isn’t technically an object, but if a variable str that is assigned the value "Howdy" calls one of the String object’s methods – e.g. charAt - then str is temporarily converted to an instance of String for as long as it takes to execute the function code.
The same goes for numbers like 123 and arrays like [ "a", "b", "c" ].
Any function inherits from the Function object which itself inherits from the Object object. In fact, Object is essentially the mother of all objects since most everything either inherits from Object directly or inherits from String, Number, Array, Boolean, or any of the other “base” objects (Date, Math, RegExp, and Global are in there, too) which themselves all inherit from Object in one glorious circle of life.
Creating objects
There are two ways to create new objects in JavaScript. The first is to define an object literal which is a collection of name-value pairs separated by commas and encased in curly braces.
var pet = {
name: "Fido",
species: "dog",
bark: function () {
alert("WOOF!");
}
};
These don’t have an explicit prototype property, but inherit “under the hood” from Object's prototype (Webkit and Mozilla browsers allow you to view an object literal’s prototype via the __proto__ property which is unavailable in Internet Explorer).
The other way to create an object is to define a constructor function that when invoked creates an object.
var Person = function (name) {
this.name = name;
};
var me = new Person("Nathaniel");
The variable me is assigned an object with only one property - name has the value "Nathaniel" - plus an “under the hood” reference to a prototype object which stores a reference to the constructor as well as a pointer to Object's prototype from which it inherits. As alluded to above the “under the hood” prototype reference is exposed in Webkit and Mozilla browsers as __proto__.
Prototypes
So what happens when you modify Person's prototype?
var Person = function (name) {
this.name = name;
};
Person.prototype.greet = function () {
alert("Hello! My name is " + this.name + ".");
};
var me = new Person("Nathaniel");
me itself remains the same with just the one name property, but __proto__ now contains a method greet. Properties and methods defined on a constructor’s prototype are available to all instances by reference, and don’t contribute to instantiation overhead.
And since the greet method is part of the prototype, which is associated to instances by reference, every instance of Person points to the same definition which itself references the name property of the specific instance.
var you = new Person("Joe Sixpack");
var her = new Person("Jennifer");
me.greet(); // Alerts "Hello! My name is Nathaniel."
you.greet(); // Alerts "Hello! My name is Joe Sixpack."
her.greet(); // Alerts "Hello! My name is Jennifer."
That’s all obvious, but it’s important to note that you can also do the following:
Person.prototype.greet = function () {
alert("Howdy, neighbor!");
};
me.greet(); // Alerts "Howdy, neighbor!"
you.greet(); // Alerts "Howdy, neighbor!"
her.greet(); // Alerts "Howdy, neighbor!"
If you change the value of any member of a constructor’s prototype all instances both existing and future recognize the change, effective immediately.
Setting up inheritance between two objects
Let’s say we want to create a new “class” object Employee that inherits from Person but has its own specialized properties or methods. First things first, let’s create the Employee constructor:
var Employee = function (name, company, title) {
this.name = name;
this.company = company;
this.title = title;
};
In order to set up inheritance between Employee and Person we need to assign Person as the prototype of Employee. There are two ways to do this.
Employee.prototype = new Person(); Employee.prototype.constructor = Employee;
The first line of code establishes that Employee's prototype should essentially be an instance of Person and thus have access to all of Person's prototype members just as any instance would. JavaScript by default assigns Person to the constructor property of Employee's prototype, however, so the second line is needed to reset Employee's constructor to Employee.
There’s a slight problem here, though, that isn’t evident in our specific example involving Person. Person's constructor is a function like any other function capable of running whatever code we feel like including. For example, let’s say Person's constructor looked like this instead of the above example:
var Person = function (name) {
this.name = name;
$("body").append('<p>New person added: ' + this.name);
};
This probably isn’t a realistic example, but the point is that the constructor function can run any code including other functions that we may not want to execute if we’re not creating a straight up instance of Person. We want to be able to grab Person's prototype without actually invoking its constructor. To do this we use a second similar technique.
var proxy = function () {};
proxy.prototype = Person.prototype;
Employee.prototype = new proxy();
Employee.prototype.constructor = Employee;
Since we don’t want to invoke Person's constructor we instead use a dummy function as a replacement constructor to instantiate as Employee's prototype. The end result is the same since Employee doesn’t care about anything in Person's constructor – it only wants to know what it should inherit through the prototype.
We still need to reset the constructor property of Employee's prototype which points to Person since it’s inherited from Person.
In either case we end up with an Employee object whose instances have a different set of constructed properties than instances of Person but have access to the greet method from Person's prototype.
Keep in mind, though, that said access to greet is still association by reference so if you change the value of greet in Person's prototype than any instance of Employee will reflect that change going forward.
The prototype chain
As objects inherit from one another they form what is popularly described as a prototype chain along which the JavaScript engine can search for a called property or method.
var e = new Employee("Steve Jobs", "Apple", "CEO");
alert(e.toString()); // Alerts "[object Object]"
When we invoke e.toString JavaScript first looks at the instance itself to see if it has a property or method of that name. Not finding such a member, JavaScript then looks at the instance’s prototype, which refers to Person's prototype, to see if there’s a toString property or method defined there. Since Person's prototype doesn’t include toString, JavaScript then has to go up the prototype chain to the next link, which happens to be the Object object. That prototype does contain a toString method which gets invoked and alerts the string representation of the object.
Only after JavaScript fails to find the property or method in question anywhere on the prototype chain does it give the undefined notification.