Workout
First we have the Workout function class. Its declaration acts as the constructor.
We have three properties: title, datetime, and notes.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
function Workout(newTitle) { //constructor this.title = newTitle; this.datetime = new Date(); this.notes = "Nothing entered yet."; this.setNotes = function(newNote) { console.log("Workout::setNotes(newNotes)"); this.notes = newNote; }; this.display = function() { console.log(" -- Workout::display(): " + this.title + " -- "); // check this property if (this.notes) { console.log("@ approximately : " + this.datetime + ", you will be doing: "); console.log(this.notes); } else { console.log(this.datetime); } // check prototype properties // whatever property we try to access, it will see if exists at 'this' object first. // if not, it will go to the 'this' object's prototype. if (this.coach){ console.log("Workout::display() - Your coach is: "+this.coach); } if (this.price) { console.log("Workout::display() - Your price is: " + this.price); } console.log("--------------------------"); }; } |
Setting the Prototype to a object literal
First, let’s define the function class Boxing. We will instantiate it, and pass it for Workout.prototype to point to.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
Boxing.classIndex = 0; Boxing.classMax = 24; function Boxing() { console.log("\n...construct Boxing object...\n"); this.price = 883; this.coach = "Joel"; this.friends = ["Allen", "Bundy"]; // since this is a compound object, instantiation of derived object shares friends. this._display = function() { console.log("----------------Boxing::_display()--------------"); console.log("Your cost: " + this.price); // this here belongs to the object. NOT the prototype. // if Boxing is acting as a prototype, the 'this' belong to the owning object. // In our case, it will check if Workout object has coach. It does not. // Then it checks the prototype which is a literal object of Boxing. // It does have coach, thus, it will display it. if (this.coach){ console.log("You will be coached by: " + this.coach); } Boxing.classIndex++; console.log("~~~ Boxing workout # " + Boxing.classIndex + " / " + Boxing.classMax); // The 'this' is evaluated to the owning derived object of Boxing prototype. // if the deriving Object (which uses this as a prototype) has a display function, this will be // true and we'll call the display function. if (typeof this.display === 'function') { console.log("Boxing::_display() - display() function declared"); this.display(); } else { console.log("Boxing::_display() - display() function NOT declared "); } }; } |
set Workout’s prototype to a Boxing literal object
1 2 3 4 |
console.log("◊ Workout.prototype = new Boxing();"); var b = new Boxing(); Workout.prototype = b; b.constructor = Workout; |
Now, the hierarchy looks like this:
All instantiation of Workout will share that literal object of type Boxing.
note:
The reason why we have a constructor property from var b is because var b (new Boxing) is the object for Workout Prototype. Thus, even though Workout is using a Boxing literal object to represent for its prototype functionality, its purpose is to be that of the Workout Prototype.
Thus, if we are to have a constructor property pointing back to Workout, any future instantiations of Workout will correctly show Workout, instead of Boxing.
1 2 3 4 5 6 |
var lesson1 = new Workout("Monday Workouts"); lesson1.setNotes("10x calisthentics"); lesson1._display(); console.log(Workout.prototype); console.log(lesson1); |
output:
Workout {
price: 883,
coach: ‘Joel’,
friends: [ ‘Allen’, ‘Bundy’ ],
_display: [Function],
constructor: [Function: Workout] }
Workout {
title: ‘Monday Workouts’,
datetime: 2018-02-05T10:11:41.560Z,
notes: ’10x calisthentics’,
setNotes: [Function],
display: [Function] }
Getting property for object with prototype
Instantiate Workout and Get a property
1) Instantiate a Workout object. It basically creates an object from our definition of Workout.
1 2 |
console.log("\n\n -- boxing lesson 1 -- \n\n"); var boxinglesson1 = new Workout("boxing workout #38"); |
2) Then let’s try using the setNotes function.
1 2 |
// set string for 'this' property boxinglesson1.setNotes("100 rounds of sparring"); |
We pass in the string to newNote. In the function the ‘this’ evaluates to our Workout instantiation. We check to see if property ‘notes’ exist in Workout. It does, and we set it to our string.
1 2 3 4 5 6 7 8 |
function Workout() { ... this.setNotes = function(newNote) { console.log("Workout::setNotes(newNotes)"); this.notes = newNote; }; ... } |
We can log properties of Workout like so:
1 2 3 |
console.log(boxinglesson1.title); console.log(boxinglesson1.datetime); console.log(boxinglesson1.notes); |
output:
boxing workout #38
2018-02-05T03:37:56.585Z
100 rounds of sparring
We then come back out to main. Since our prototype is set to Boxing object literal, let’s see what happens when we try to access property coach.
1 |
console.log("boxinglesson1.coach: "+boxinglesson1.coach); |
It displays the string “Joel”.
- First, it will see if the property “coach” exists in the Workout object. It does not.
- Because it does not, it will go to its prototype and check there.
- The prototype object is Boxing. And Boxing does have “coach” property initiated to Joel.
Hence, “Joel” is displayed.
1 2 |
// reads the prototype property console.log("boxinglesson1.coach: "+boxinglesson1.coach); |
Keep in mind that all instantiations will share this Boxing object literal.
If we were to create another Workout object, it will display the same coach.
1 2 |
var boxinglesson2 = new Workout("boxing lessons 2"); console.log("boxinglesson2.coach: "+boxinglesson2.coach); |
output:
boxinglesson1.coach: Joel
boxinglesson2.coach: Joel
Let’s evaluate the prototype to see what it looks like:
1 |
console.log(Workout.prototype); |
Boxing {
price: 883,
coach: ‘Joel’,
friends: [ ‘Allen’, ‘Bundy’ ],
_display: [Function] }
Let’s change the coach property to someone else:
1 |
Workout.prototype.coach = "Rex"; |
Now, as you can see, we literally changed the prototype’s property to something “Rex”. And this gets reflected to other instantiations has their prototype property set to this object.
1 |
console.log(Workout.prototype); |
output:
Boxing {
price: 883,
coach: ‘Rex’,
friends: [ ‘Allen’, ‘Bundy’ ],
_display: [Function] }
1 2 |
console.log("boxinglesson1.coach: "+boxinglesson1.coach); console.log("boxinglesson2.coach: "+boxinglesson2.coach); |
boxinglesson1.coach: Rex
boxinglesson2.coach: Rex
code:
1 2 3 4 5 6 7 8 9 10 11 |
var boxinglesson1 =new Workout(); // set string for 'this' property boxinglesson1.setNotes("100 rounds of sparring"); boxinglesson1._display(); var boxinglesson2 = new Workout(); Workout.prototype.coach = "Rex"; // reads the prototype property console.log("boxinglesson1.coach: "+boxinglesson1.coach); console.log("boxinglesson2.coach: "+boxinglesson2.coach); |
Calling prototype object’s functions
Let’s set the coach property back to Joel
1 |
Workout.prototype.coach = "Joel"; |
Let’s look at prototype function _display
We must take heed that the this in the function belongs to the instantiated object, NOT the prototype. In our case, ‘this’ is an instantiation of Workout.
Thus, when we try to do something like this.coach, it will first check Workout object to see if it has a property called coach.
Because it does not, it will then go to the prototype and check for a coach property. In our case, it does.
Therefore, in our function, this.coach is valid (Joe) and thus, will display Joel in the function.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
this._display = function() { console.log("----------------Boxing::_display()--------------"); if (this.coach){ console.log("You will be coached by: " + this.coach); } Boxing.classIndex++; console.log("~~~ Boxing workout # " + Boxing.classIndex + " / " + Boxing.classMax); if (typeof this.display === 'function') { console.log("Boxing::_display() - display() function declared"); this.display(); } else { console.log("Boxing::_display() - display() function NOT declared "); } }; |
You will also notice we check if to see if this.display is a function. The this in question is the instantiation of Workout. Thus, we are asking Workout if it has a display function. It evaluate to true, and thus, we call Workout’s display function.
1 2 |
// calls prototype function boxinglesson1._display(); |
output
Boxing::_display() – display() function declared
— Workout::display(): boxing workout #38 —
@ approximately : Mon Feb 05 2018 11:43:48 GMT+0800 (CST), you will be doing:
100 rounds of sparring
Workout::display() – Your coach is: Joel
Workout::display() – Your price is: 883
————————–
Setting Properties for Objects with Prototype
When we were getting properties, JS first evaluates your instantiated object. Then if it doesn’t exist, it will go up to the prototype object. If it doesn’t exist there, then it will return undefined.
When we’re setting properties, its much more limited. Due to all instantiations share a common prototype object
we cannot set/change a prototype property through an instantiation of an object.
The only way to do is through accessing the prototype object itself like so:
1 |
Workout.prototype.coach = "KaTu". |
Then, all instantiations of Workout will have prototype property coach “Katu”.
If you were to try to set a prototype property like this:
1 2 3 4 5 |
var boxinglesson3 =new Workout("boxing workout #12"); // set string for 'this' property boxinglesson3.setNotes("Run 10 kms"); boxinglesson3.coach = "Sismundo"; boxinglesson3._display(); |
At first, you may think you have successfully set the prototype’s coach property.
output
—————-Boxing::_display()————–
Your cost: 883
You will be coached by: Sismundo
~~~ Boxing workout # 2 / 24
Boxing::_display() – display() function declared
— Workout::display(): boxing workout #12 —
@ approximately : Mon Feb 05 2018 11:58:22 GMT+0800 (CST), you will be doing:
Run 10 kms
Workout::display() – Your coach is: Sismundo
Workout::display() – Your price is: 883
————————–
But upon closer inspection, you’ll see that instantiations DO NOT allow you to set its prototype’s properties.
Instead, because you try to set a property that does not exist at the instantiation level, it will add the property for you. In our example, it added property coach to your Workout instantiation.
1 2 |
console.log(boxinglesson3); console.log(Workout.prototype); |