Function notes
To go back to the README where all the chapters are: click here.
- 7.1 Updates to Functions
- 7.2 Arrow Functions
- 7.3 Using Arrow Functions
- 7.4 Quiz: Convert Function into an Arrow Functions
- 7.5 Arrow Functions Recap
- 7.6 Arrow Functions and the "this" Keyword
- 7.7 "this" and Regular Functions
- window Binding
- 7.8 "this" and Arrow Functions
- 7.9 Default Function Parameters
- 7.10 Defaults and Destructuring
- 7.11 Quiz: Using Default Function Paramters (2 - 2)
- 7.12 Class Preview
- 7.13 Javascript’s Illusion of Classes
- 7.14 Javascript Classes
- 7.15 Convert a Function to a Class
- 7.16 Working with JavaScript Class
- 7.17 Super and Extends
- 7.18 Extending Classes from ES5 to ES6
- 7.19 Working with JavaScript Subclasses
- 7.20 Quiz: Building Classes and Subclasses (2 - 3)
- 7.21 Lesson 2 Summary
Here is a little introduction to what the lesson will be about.
The checklist on the previous chapter was this. Now we can check off Syntax since we completed chapter 6.
-
✓ Lesson 1 - Syntax - changes and addition to the Javascript Syntax.
-
❏ Lesson 2 - Functions - We will investigate updates to JavaScript Functions.
-
❏ Lesson 3 - Built-Ins - We will cover new ES6 built ins.
-
❏ Lesson 4 - Developer-Fu - We will wrap things up by showing you how you can incorporate these latest updates into your next JavaScript project.
The two instructors covers what we will be trying to learn in this lesson.
-
We will learn the new way to write functions called arrow functions.
-
We will also be learning about the new class keyword that lets you create functions as classes.
-
With the new ES6 we can now set the default function parameters.
-
We can connect different classes together using the new super and extends keywords.
We’re introduced to a new and easier way to write functions. This uses the fat arrow in place of function.
Here is the old way to write a function…. In this example we use the .map() method that functions on every element of an array and then gathers the returned values from each function call and makes a new array with the results.
const upperizedNames = ['Farrin', 'Kagure', 'Asser'].map(function(name) { return name.toUpperCase(); });
and then here’s the new way using the ⇒
const upperizedNames = ['Farrin', 'Kagure', 'Asser'].map( name => name.toUpperCase() );
This new method of creating functions makes it a whole lot more easier to understand.
No more need for function(x) {code} now it’s just x ⇒ code.
Functions can either be function declarations or function expressions.
Before I move on with this subject, I need to understand what those two mean.
-
Function declaration is a function that doesn’t require variable assignment. They are standalone and cannot be nested within non-function blocks. They also must start with function and then name just like how variables must start with var/let/const and then name.
function nameOF(a, b) { return a + b; } nameOf(3, 2) // 5 nameOf // function
-
Function expression can be named or it can be anonymous. Function expressions cannot start with function. Typically function expressions are part of a larger expression syntax.
example of a function expression:
var a = function() { //anonymous } var a = function b() { // named }
okay, I think I can move on now…
Arrow functions can only be expressions. The full name of function expression is arrow function expressions. So that mean they have to follow the same rules as a function expression.
-
stored in a variable
-
passed as an argument to a function
-
and stored in an object’s property.
Now writing it can get a bit confusing.
old way for greet('Asser')
const greet = (function(name)) { return 'Hello' + name; }
now it’s a whole lot more simpler with the arrow function
Here’s one with only one parameter
const greet = name => `Hello ${name}`; or const greet = (name) => `Hello ${name}`;
both will print: Hello Asser. In these cases they only have one parameter to worry about. Now what if there are two or more items in the parameter list? And what if there are none?
-
Here’s how it would look like if it was an empty parameter. Seems to require the paranthesis or you can use an underscore in place of the empty paranthesis.
const greet = () => code or const greet = _ => code
-
multiple parameters also requires the paranthesis.
const greet = (name, age) => code
Note
|
The underscore was entirely new to me so I had to go look it up. Another user mentions that () gives the impression that there will not be any arguments so it never bothered to declare any parameter. Though if you use the underscore, you’re telling the function that there will be arguments, but maybe not so just leave the space open. I’m not entirely sure about all of this though, so I may have to do more research. For right now the underscore just replaces the empty paranthesis. |
They gave the quiz before talking about this which I thought was unfair. So what does concise and block body syntax mean when it comes to writing functions?
-
concise body function
Up until now, we’ve been using a concise body syntax which means-
has no curly braces surrounding the function body
-
and automatically returns the expression.
-
example:
const upperizedNames = ['Farrin', 'Kagure', 'Asser'].map( name => name.toUpperCase() );
-
block body function
This is needed for when you have more than a single line of code in the arrow function. Though, you can still use this method for a single line if you want to.-
it uses curly braces to wrap the function body
-
A return statement needs to be used to actually return something from the function.
-
example:
const upperizedNames = ['Farrin', 'Kagure', 'Asser'].map( name => { name = name.toUpperCase(); return `${name} has ${name.length} characters in their name`; });
The question is "Which of the following choices have the correctly formatted arrow functions?"
Note
|
You can use an underscore to replace the empty paranthesis. They will both result in undefined and maybe an underscore would be better in a sea of paranthesis. I can’t seem to find anymore information on this so maybe I’ll update this post once I do. |
The way it was written confused me so I’m just going to lay it out here. Also, quiz 1 was introduced before talking about concise and block body, so ignore the "must have a return with block" rule for this one.
1 setTimeout( () => { console.log('starting the test'); test.start();}, 2000);
empty parameter and uses block body > yes
2 setTimeout( _ => { console.log('starting the test'); test.start();}, 2000);
empty parameter and uses block body > yes
3 const vowels = 'aeiou'.split(''); const bigVowels = vowels.map((letter) => letter.toUpperCase());
single parameter and uses concise body > yes
4 const vowels = 'aeiou'.split(''); const bigVowels = vowels.map(letter => letter.toUpperCase());
single parameter and uses concise body > yes
Question: Which of these used the correctly formatted arrow functions?
1 const color = ['red', 'blue', 'green', 'yellow', 'orange, 'black']; const crazyColors = colors.map( color => { const jumble = color.split('').reverse(); return jumble.join('') + '!'; });
-
✓ block body function must have a return
2 const color = ['red', 'blue', 'green', 'yellow', 'orange, 'black']; const crazyColors = colors.map( color => { colors.split('').reverse().join('') + '!'; });
-
❏ block body function must have a return
3 const color = ['red', 'blue', 'green', 'yellow', 'orange, 'black']; const crazyColors = colors.map( color => return color.split('').reverse().join('') + '!');
-
❏ concise body should not have a return.
4 const color = ['red', 'blue', 'green', 'yellow', 'orange, 'black']; const crazyColors = colors.map( color => color.split('').reverse().join('') + '!');
-
✓ concise body should not have a return.
Quiz time!
This one was a breeze considering we spent so much time on the previous!
All we had to do was change the old function to the arrow function
const squares = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map(function(square) { return square * square; });
is now:
or
const squares = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map(square => { return square * square};
So far I am really enjoying the new arrow functions. Especially the fact we don’t need to type in the function keyword anymore. And if we’re using the concise version, we don’t need {} and return anymore. Unfortunately, it doesn’t replace all functions. The arrow functions are only for for function expressions.
Now they’re telling us that there’s another drawback to arrow functions. The this keyword is different from the regular functions.
More on that coming right up.
The instructors mention that this works differently in arrow functions.
-
The Regular Functions way of this is how the function is called.
-
The Arrow Functions way of this is where it’s located in the code.
In this section I’m going to try and relearn this by using this video rather than the lesson. I just thought the short chapter on this was a bit confusing.
Implicit binding says when the function is being called, look to the left and that is where this keyword is going to reference.
-
var Person has the parameters: name and age. Inside were the objects: name, age, and sayName. sayName uses this.name which refers to Person.name.
-
var jim puts in the arguments: 'Jim', 42 for Person's name and age parameter. this was stored with jim.
-
jim.sayName(); will call sayName using jim’s arguments.
Now what if the function is separated from the object? We need to use .call for it to communicate with each other.
This would print: My name is Stacey.
In this example we want to use the function with the stacey object.
SayName is the function. this needs to be connected or else it would be confused where to refer to.
This will print: My name is Stacey and I know JavaScript, Ruby, and Python.
This will work, but there’s an easier way to pass in what’s in the array of languages and parse it for us into the parameters. That’s where .apply() comes in.
.bind() is a lot like .call as in they work one-by-one, but they’re best for creating an entirely new function that can be called later.
So this is how .call() would have worked:
var sayName = function(lang1, lang2, lang3) { console.log(`My name is ${this.name} and I know ${lang1}, ${lang2}, and ${lang3}`); }; var stacey = { name: 'Stacey', age: 34 }; var languages = ['JavaScript', 'Ruby', 'Python'] sayName.call(stacey, languages[0], languages[1], languages[2]);
With .bind we’re binding it into a new function.
var newFn = sayName.bind(stacey, languages[0], languages[1], languages[2]);
so now we can just call the newF to get the same result.
newFn()
In short, call() and apply() behave the same way by instantly invoking the function. .call() will pass in arguments one by one, while .apply() will pass the arrays.
.bind() will behave the same way as .call() but instead of instantly invoking the function, it will instead give us a brand new function that we can call later.
if we ran this:
var sayAge = function() { console.log(this.age); } var me = { age: 25 } sayAge()
We would get undefined because there’s nothing to the left of the sayAge(), not using the new Binding, and not using call/apply/bind, it will then default to the global window binding.
If we still wanted to call using sayAge() we would have to create window.age = 25; to give us the result we want.
The new Binding is with the constructor function. Using the new Binding keyword with the variable myFather will create a new object and bound this with the new object.
function Person(first, last, age, eye) { this.firstName = first; this.lastName = last; this.age = age; this.eyeColor = eye } var myFather = new Person("John", "Doe", 50, "blue"); console.log(`My father is ${myFather.age}.`)
Okay that was long, but I think I understand how this works now.
The convenience with the arrow function is that this inherits the value from the surrounding context.
This is how the regular function would have worked with the constructor function.
pink would print out: I currently have 3 scoops
"But now I have NaN scoops!"
Now here’s the new arrow function.
pink would print out: I currently have 3 scoops
red would print out: But now I have 6 scoops
Note
|
if addScoop() used an arrow function along with setTimeOut(), this would refer to global instead. |
If there’s no argument put in for the parameter, there’s a way to give it a default value.
The old way you had to write a bit too much. Honestly, I never even knew it. Glad it was replaced. Here’s the old way:
function greet(name, greeting) { name = (typeof name !== 'undefined') ? name : 'Student'; greeting = (typeof greeting !== 'undefined') ? greeting : 'Welcome'; return `${greeting} ${name}!`; } greet(); // Welcome Student! greet('James'); // Welcome James! greet('Richard', 'Howdy'); // Howdy Richard!
Now there’s a new way. All we now have to do is put the default values right inside the parameters.
function greet(name = 'Student', greeting = 'Welcome') {
return ${greeting} ${name}!
;
}
greet(); // Welcome Student!
greet('James'); // Welcome James!
greet('Richard', 'Howdy'); // Howdy Richard!
Note
|
Just in case it wasn’t clear, the default values are right inside the parameters like this (parameter1 = 'default string', parameter2 = default integer) |
Here’s a little refresher on what destructuring is:
The destructuring assignment syntax is a JavaScript expression that makes it possible to unpack values from arrays, or properties from objects, into distinct variables.
Before we get into destructuring and defaults together, I suppose we need to understand why we would need the two together in the first place.
When we work with array parameters and defaults, we would put in:
function createGrid([width = 5, height = 5]) { return `Generates a ${width} x ${height} grid`; }
-
If we had called with createGrid([]) it would give us the defaults: Generates a 5 x 5 grid.
-
If we had called with createGrid([3, 2]) it would give us the new: Generates a 3 x 2 grid.
-
If we had called with createGrid([undefined, 3]); it would give us the default along with the new digit Generates a 5 x 3 grid.
What if we called it with just the basic createGrid()?
We would get an error: Uncaught TypeError: Cannot read property 'Symbol(Symbol.iterator)' of undefined.
We get this error because createGrid() expects an array to be passed so it can destructure it. But since the function was called without an array, it will break. To fix this default issue, we insert an empty bracket.
function createGrid([width = 5, height = 5] = []) { return `Generates a ${width} x ${height} grid`; }
In this case, if createGrid() is called without any argument, it will call its other default since it was expecting an array.
function createGrid([width, height] = [5, 5])
Since the array is empty, there’s nothing to destructure so then it will default to the original: width = 5, height = 5.
Giving the function the extra = [] is like giving the call createGrid([]).
REMINDER: Destructuring Arrays in defaults also goes by position.
With the following code, which of the options will not run without throwing an error:
function houseDescriptor([houseColor = 'green', shutterColors = ['red']]) { return `I have a ${houseColor} house with ${shutterColors.join(' and ')} shutters`; }
With this function, I gave it a must have list:
-
❏ Everything must be encased in an array.
-
❏ First parameter is a string or undefined
-
❏ Second parameter must be an array or undefined.
Option 1: If we had put in:
houseDescriptor('red',['white', 'gray', 'pink'])
We get a TypeError
Because houseDescriptor is only expecting an array argument. This option doesn’t work because it’s calling the function with a string and an array.
the rules result:
-
❏ Everything must be encased in an array.
-
✓ First parameter is a string or undefined
-
✓ Second parameter must be an array or undefined.
Note
|
Now of course if we had written the function as: function houseDescriptor(houseColor = 'green', shutterColor = ['red']) {} then calling it as: houseDescriptor('red',['white', 'gray', 'pink']); would have worked. |
Option 2:
houseDescriptor(['green', ['white', 'gray', 'pink']]);
This would work because everything is encased into an array like the function was written. Which was:
<array>
<string>default</string> ,
<array> default </array>
</array>
So according to the rules that the function wrote, it passed all of them.
-
✓ Everything must be encased in an array.
-
✓ First parameter is a string or undefined
-
✓ Second parameter must be an array or undefined.
Option 3:
houseDescriptor(['blue', 'purple']);
It passed a bunch of the rules except that the second parameter needed to be an array or left out.
-
✓ Everything must be encased in an array.
-
✓ First parameter is a string or undefined.
-
❏ Second parameter must be an array or undefined.
Though if you had ran the code, an error wouldn’t pop up. The second parameter would just ignore it and default on its own. We wanted to use use 'purple' so this option would be wrong.
Option 4:
houseDescriptor(['green']);
Well this is an obvious one. It’s in an array like what is required. It’s just missing the second argument, but since there’s a default option, I guess we don’t need it. Like what was mentioned earlier, it could even be: houseDescriptor([])" and it’ll give the default: green and red.
-
✓ Everything must be encased in an array.
-
✓ First parameter is a string or undefined.
-
✓ Second parameter must be an array or undefined.
Fortunately object destructuring in defaults works the same way as array destructuring in defaults. I’m relieved how easy this part is and I can give my brain a break.
A function can have an object be a default parameter and use object destructuring. It is basically the same as the array but of course, instead of an array, it would be an object.
for example:
function createSundae({scoops = 1, toppings = ['Hot Fudge']}) { const scoopText = scoops === 1 ? 'scoop' : 'scoops'; return `Your sundae has ${scoops} ${scoopText} with ${toppings.join(' and ')} toppings.`; } createSundae({}); // Your sundae has 1 scoop with Hot Fudge toppings. createSundae({scoops: 2}); // Your sundae has 2 scoops with Hot Fudge toppings. createSundae({scoops: 2, toppings: ['Sprinkles']}); // Your sundae has 2 scoops with Sprinkles toppings. createSundae({toppings: ['Cookie Dough']}); // Your sundae has 1 scoop with Cookie Dough toppings.
Now if we tried to call it without any arguments
createSundae();
This would throw an error
The same reason as the array. So to work around this issue, we would have to edit the function to include an empty object.
function createSundae({scoops = 1, toppings = ['Hot Fudge']} = {})
So in case an empty argument is called, it will call the empty object which will then call the defaulted object.
Code Reminder about object destructuring.
The difference with arrays and object is that arrays are referenced by their position. Object on the other hand, is referenced by their given name.
Deconstructed object’s order does not matter and if we had left out an item, it would be ignored.
Using the code below, which call wouldn’t throw an error?
function houseDescriptor({houseColor = 'green', shutterColors = ['red']} = {}) { return `I have a ${houseColor} house with ${shutterColors.join(' and ')} shutters`; }
With that, I had to make a new checklist
-
❏ Would have to be encased in a set of curly brackets or an empty call.
-
❏ first parameter has to be a string or undefined.
-
❏ second parameter has to be an array or undefined.
Option 1:
houseDescriptor({houseColor:'red', shutterColors:['white', 'gray', 'pink']});
-
✓ Would have to be encased in a set of curly brackets or an empty call.
-
✓ first parameter has to be a string or undefined.
-
✓ second parameter has to be an array or undefined.
Option 2
houseDescriptor({houseColor:'red'});
-
✓ Would have to be encased in a set of curly brackets or an empty call.
-
✓ first parameter has to be a string or undefined.
-
✓ second parameter has to be an array or undefined.
Option 3
houseDescriptor();
-
✓ Would have to be encased in a set of curly brackets or an empty call.
-
✓ first parameter has to be a string or undefined.
-
✓ second parameter has to be an array or undefined.
Option 4:
houseDescriptor({shutterColors:['orange', 'blue']});
-
✓ Would have to be encased in a set of curly brackets or an empty call.
-
✓ first parameter has to be a string or undefined.
-
✓ second parameter has to be an array or undefined.
Option 5:
houseDescriptor({})
-
✓ Would have to be encased in a set of curley brackets or an empty call.
-
✓ first parameter has to be a string or undefined.
-
✓ second parameter has to be an array or undefined.
There’s this little section mentioning the difference between having to leave out an argument with Objects and Arrays. Objects we could just mention the name or don’t mention it at all. Arrays, on the otherhand, in place of the one we want to skip, we have to put undefined. However, when I tested it with just an empty
, ,
that works too.
Quiz time!
This is a quiz we have to create our own function with the name: buildHouse() with 3 default parameters.
Here are the default values they want inserted
floors = 1 color = 'red' walls = 'brick'
Here is what the function is going to be tested with:
console.log(buildHouse()); // Your house has 1 floor(s) with red brick walls. console.log(buildHouse({})); // Your house has 1 floor(s) with red brick walls. console.log(buildHouse({floors: 3, color: 'yellow'})); // Your house has 3 floor(s) with yellow brick walls.
According to those calls, there’s a checklist we have to make.
-
❏ There has to be a fallback. Either it would be ([array] =[]) or ({object} = {})
-
❏ It has to be an object.
-
❏ It has to take 3 parameters.
Answer:
function buildHouse({floors = 1, color = 'red', walls = 'brick'} = {}) { return `Your house has ${floors} floor(s) with ${color} ${walls} walls.` }
The instructors want to show us classes. Here’s a little preview.
class Dessert { constructor(calories = 250) { this.calories = calories; } } class IceCream extends Dessert { constructor(flavor, calories, toppings = []) { super(calories); this.flavor = flavor; this.toppings = toppings; } addTopping(topping) { this.toppings.push(topping); } }
They gave us some questions.
-
What’s this class keyword?
-
What’s this extends keyword inside Icecream extends Dessert?
-
What’s that Super() call inside IceCream’s constructor?
I believe there will be more of that coming up….
To avoid confusion, let’s ignore what the instructors say about what other languages do with classes and just focus on what JavaScript does with it.
Javascript is not a class based language, but uses functions to create objects, and links objects together with prototype inheritance. The new keywords: class, super, and extends doesn’t change anything in the language. It’s just a new and cleaner way to write in JavaScript.
Before we get started with classes, I figured I needed to understand prototype inheritance first.
With the code they provided let’s try to understand prototype…
function Plane(numEngines) { this.numEngines = numEngines; this.enginesActive = false; } // methods "inherited" by all instances Plane.prototype.startEngines = function () { console.log('starting engines...'); this.enginesActive = true; }; const rich = new Plane(1); const james = new Plane(4);
const rich = new Plane(1)
and
const james = new Plane(4)
when rich and james used new Plane(1), they created their own constructor function with their own number of engines in the parameter. What’s happening here is that now we have two copies of Plane.
Plane.prototype.startEngines = function() {…} is the function that james and rich will use.
The way I see it, prototype is like the shared folder that the two computers in the network can all access. Prototype boils down to being easier to keep track of and also it stores less data.
If we had skipped prototype and just stored our startEngine right inside the Plane constructor like this:
function Plane(numEngines) { this.numEngines = numEngines; this.enginesActive = false; this.startEngines = function() { console.log('starting engines...'); this.enginesActive = true; } }
this would happen inside the hood:
Now if we stored the startEngines prototype for Plane constructor like this:
function Plane(numEngines) { this.numEngines = numEngines; this.enginesActive = false; } Plane.prototype.startEngines = function() { console.log('starting engines...'); this.enginesActive = true; }
rich and james would look like this under the hood:
startEngine function is stored in the shared proto area.
In ES6, this does the same thing as the Plane constructor and startEngine prototype
class Plane { constructor(numEngines) { this.numEngines = numEngines; this.enginesActive = false; } startEngines() { console.log('starting engines…'); this.enginesActive = true; } }
We’ll find out more coming right up.
The changes are actually a lot more straightforward than I thought and I’m actually loving it.
What’s new:
-
There’s now a class function that you can store these methods in. Instead of of the constructor function with the name, class now has the name.
-
There’s a new method name called constructor which has all the information for objects to create with.
-
You can now create your prototype inside the class function. No need to type in Name.Prototype.propertyName to link the two together.
Class is just a function. To test it out, put this in:
class Plane { constructor(numEngines) { this.numEngines = numEngines; this.enginesActive = false; } startEngines() { console.log('starting engines…'); this.enginesActive = true; } } typeof Plane; // function
This is a reminder quiz to check if you’ve been paying attention.
When it comes to this code, which of the options are true?
class Animal { constructor(name = 'Sprinkles', energy = 100) { this.name = name; this.energy = energy; } eat(food) { this.energy += food / 3; } }
Option 1:
The eat() method ends up on Animal.prototype
Option 2:
typeof Animal === 'class'
Option 3:
typeofAnimal === 'function'
Option 1 and 3 being correct.
Option 1 because eat() will be Animal’s prototype since it’s separate from the constructor.
Option 3 because class is a function and not its own entity.
The topic is very confusing unless we know more about Object Oriented JavaScript
There’s an entire class on it: Udacity Object Oriented Javascript.
It’s quite long… I might take it if I have time. In the meantime I’ll just be confused about static methods and hope it’s never referenced again.
In the meantime… to create a static method, all we have to do is add static in front of the name like this example with badweather()
class Plane { constructor(numEngines) { this.numEngines = numEngines; this.enginesActive = false; } static badWeather(planes) { for (plane of planes) { plane.enginesActive = false; } } startEngines() { console.log('starting engines…'); this.enginesActive = true; } }
From this short sentence on what static methods mean when it comes to classes is that badweather() is a method that’s accessed directly on the Plane class.
Here we’re introduced to Super and Extends with this code
class Tree { constructor(size = '10', leaves = {spring: 'green', summer: 'green', fall: 'orange', winter: null}) { this.size = size; this.leaves = leaves; this.leafColor = null; } changeSeason(season) { this.leafColor = this.leaves[season]; if (season === 'spring') { this.size += 1; } } } class Maple extends Tree { constructor(syrupQty = 15, size, leaves) { super(size, leaves); this.syrupQty = syrupQty; } changeSeason(season) { super.changeSeason(season); if (season === 'spring') { this.syrupQty += 1; } } gatherSyrup() { this.syrupQty -= 3; } }
-
extend in class Maple extends Tree is a subclass for Tree.
-
the keyword super is used to get from the subclass to the parent class.
-
super is used two different ways when it comes to the classes. Maple’s constructor super was a function, but in Maple’s changeSeason() method super was an object.
This section is just explaining the difference between ES5 and ES6 when it comes to constructors and their prototypes.
Left: ES5 |
Right: ES6 |
|
a |
Tree custructor function all alone |
Tree is now a class and the constructor is inside the Tree class |
b |
prototype changeSeason is linked with Tree by having the name Tree.prototype.changeSeason |
prototype changeSeason is inside the class Tree which is how they will be linked. |
c |
A constructor function all alone. However you would have to link it somehow… see c.1 and c.2 |
To link the subclass to the parent class, We have to give it the name: class Maple extends Tree |
c.1 |
We have to set Maple’s prototype to the parent’s prototype with: Maple.prototype = Object.create(Tree.prototype); |
|
c.2 |
Since we overwrote the original prototype object, we need to remake the connection from the constructor property to the original constructor function by typing in: Maple.prototype.constructor = Maple |
|
c.3 |
For subclass Maple to call parent class Tree you need to use .call. Tree.call this, size, barkColor, leaves); |
For subclass Maple to call parent class Tree we need to use the keyword super super(size, barkColor, leaves) |
d |
To call a prototype method from changeSeason to its parent you also use .call Tree.prototype.changeSeason.call(this, season); |
To call a prototype method from changeSeason to its parent you also use super. super.changeSeason(season); |
A reminder about classes and subclasses: They do not gets hoisted up.
So when it comes to subclasses and you’re going to refer to its parent with this keyword, you need to call it with super and then under it you can use this.
in this code
class Toy {} class Dragon extends Toy {} const dragon1 = new Dragon();
With the code above, is the following statement true or false?
dragon1 instanceof Toy;
Answer: True because Dragon is a subclass of Toy.
These are all just checking to see if you’ve been paying attention.
Question
Let’s say that a Toy class exists and that a Dragon class extends the Toy class.
What is the correct way to create a Toy object from inside the Dragon class’s constructor method?
Answer
We learned the new way to call from subclass to parent class is to use super()
-
Here we have to create our own subclass Bicycle for the Vehicle class.
-
Bicycle has to change the defaults to wheels = 4 and horn = 'honk honk'
Note
|
You have to put in all of the parameters into the new subclass and just not the ones you want to change. |
Here’s the main class:
class Vehicle { constructor(color = 'blue', wheels = 4, horn = 'beep beep') { this.color = color; this.wheels = wheels; this.horn = horn; } honkHorn() { console.log(this.horn); } }
and here is what they’ll test with:
const myVehicle = new Vehicle(); myVehicle.honkHorn(); // beep beep const myBike = new Bicycle(); myBike.honkHorn(); // honk honk
Answer
class Bicycle extends Vehicle { constructor(color, wheels = 2, horn = 'honk honk') { super(color, wheels, horn); } }