×
By the end of this chapter, you should be able to:
new
keyword has on an object's prototypeEvery single function that is created in JavaScript has a prototype
property. Moreover, each object that is created can access its constructor's prototype property via the object's own __proto__
property.
Let's start by looking at Object.prototype
. In the Chrome console, try typing Object.prototype
then expand the object you get back. You can see that Object
already has many properties on its prototype.
When you create a constructor function, that function will have it's own prototype. Let's try that out by creating a Person
constructor function:
function Person(name) { this.name = name; } var tim = new Person("Tim"); Person.prototype; // Object {}
So far, our Person
constructor function has a prototype and the only two properties available on the prototype should be constructor
and __proto__
. Let's try adding a function to the Person prototype:
Person.prototype.sayHello = function() { return "Hello, " + this.name; };
Now that we have added sayHello
to the prototype of Person
, any person object that will be create or that was created in the past has access to the function:
var moxie = new Person("Moxie"); moxie.sayHello(); // returns "Hello, Moxie" // Notice that sayHello still works for tim even though tim was created // before the sayHello function was added to the prototype. tim.sayHello(); // returns "Hello, Tim"
So the main things to know so far about an Object's prototype are the following:
Person
instances).This video discusses prototypes in a bit more detail:
Let's look at another example of adding properties to a prototype.
function Person(name){ this.name = name; } Person.prototype.siblings = ["Haim", "David"]; var elie = new Person("Elie");
The above example creates a instance of a Person
and sets a siblings
array on the prototype. The intention is for elie
to have an array of siblings. However, since the prototype is shared among all instances of a Person
, any other instance will also have access to the same siblings array:
elie.siblings.push("Tamar"); // returns the new length of the array => 3 // The siblings array will now be ["Haim", "David", "Tamar"] var anotherPerson = new Person("Mary"); anotherPerson.siblings.push("Leslie"); elie.siblings; // ["Haim", "David", "Tamar", "Leslie"]
We can see again from this example, that anything put on the prototype is shared among all instances of that object.
This video provides more detail on how objects can share properties and methods via a common prototype:
The best practices for creating constructor functions in JavaScript are:
Using our person example, if we want to add a siblings array to the Person
class, we would add it in the constructor:
function Person(name) { this.name = name; this.siblings = []; } var janey = new Person("Janey"); janey.silbings.push("Annie");
Now each time the new
keyword is used on the Person
constructor, a new object is created that has its own name and siblings property. Now if we create another person it will have its own name and siblings array as well:
var tim = new Person("Tim"); tim.siblings.push("Nicole"); tim.siblings.push("Jeff"); tim.siblings.push("Greg"); tim.siblings; // Returns ["Nicole", "Jeff", "Greg"];
We said earlier that when it comes to functions, you typically want to add them to the prototype. Why is this? After all, your code will function correctly if you create your function definitions in the constructor like this:
// NOT A GOOD PRACTICE function Person(name) { this.name = name; this.sayHi = function() { return "Hello, " + this.name; } }
The problem is that every time you use the new
keyword to create a Person
, a new object gets created in memory that allocates space for the person's name and also for the sayHi
function. So if we have 10 Person
objects that we create, there will be 10 copies of the same sayHi
function. Since the function does not need to be unique per Person
instance, it is better to add the function to the prototype, like this:
// BEST PRACTICE!! function Person(name) { this.name = name; } Person.prototype.sayHi = function() { return "Hello, " + this.name; }
Unless you have a good reason not to, always put function definitions on the constructor function's prototype.
When you attempt to access a property on an object in JavaScript, there is a lookup process that goes on in order to find your property. To find the value for a property, first the properties on the object are checked. If the property is not found, then the properties on the prototype of the constructor function are checked. Let's look at an example:
function Automobile(make, model, year) { this.make = make; this.model = model; if (year !== undefined) { this.year = year; } } Automobile.prototype.year = 2016;
Notice that year is set on the prototype to 2016. Also, if no year is passed into the constructor, an assignment to year will not be made.
var newCar = new Automobile("Ferrari", "488 Spider"); // In this case, we did not pass in a year, // so it was never set in the constructor function newCar.hasOwnProperty("year"); // Returns false newCar.year; // returns 2016
Now, if we create a car with a year, the property on the car object will be seen first in the property lookup:
var probe = new Automobile("Ford", "Probe", 1993); probe.hasOwnProperty("year"); // returns true probe.year; // returns 1993
These videos offer some exercies (and solutions) on constructor functions and prototypes:
Complete the Prototypes Exercise
When you're ready, move on to Inheritance