Skip to content

Latest commit

 

History

History
1252 lines (865 loc) · 35.8 KB

ch7.asciidoc

File metadata and controls

1252 lines (865 loc) · 35.8 KB

Grow with Google Challenge Notes: Chapter 7 aka Lesson 2

7.1 Updates to Functions

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.

7.2 Arrow Functions

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.

7.3 Using Arrow Functions

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.

Writing the arrow function

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.


concise and block body syntax

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`;
});

arrow function quiz 1

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


arrow function quiz 2

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.


7.4 Quiz: Convert Function into an Arrow Functions

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:

const squares = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map(square => square * square);

or

const squares = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map(square => { return square * square};

7.5 Arrow Functions Recap

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.

7.6 Arrow Functions and the "this" Keyword

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.

7.7 "this" and Regular Functions

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

this1
This would print out his name Tyler.

Implicit binding says when the function is being called, look to the left and that is where this keyword is going to reference.


Here’s a more complicated scenario:
this2
This would print out only his name: Jim.

  • 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.

Explicit Binding with .call, .apply, .bind

call()

Now what if the function is separated from the object? We need to use .call for it to communicate with each other.

this3
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.


apply()

Now what if there’s an array? This is how .call() may not be the best.
this4

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.

this5
So instead of .call() which we will have to manually call one by one, .apply() will pass an array of arguments and match it for us.

bind()

.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()

summary of call, apply, bind

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.

window Binding

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.

+ this6

new Binding

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.

7.8 "this" and Arrow Functions

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.

this8

pink would print out: I currently have 3 scoops

"But now I have NaN scoops!"

Now here’s the new arrow function.

this7

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.

7.9 Default Function Parameters

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)

7.10 Defaults and Destructuring

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.

Array Destructuring and defaults.

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.

destArr2
So if you wanted to leave anything out, you would need to include an empty , , for that position.

Quiz 1 of 2 - Array Destructuring in defaults

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.

Object destructuring in defaults.

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.
destOBJ2
Deconstructed object’s order does not matter and if we had left out an item, it would be ignored.

Quiz 2-2 Object Destructuring in Defaults

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.

7.11 Quiz: Using Default Function Paramters (2 - 2)

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.`
}

7.12 Class Preview

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.

  1. What’s this class keyword?

  2. What’s this extends keyword inside Icecream extends Dessert?

  3. What’s that Super() call inside IceCream’s constructor?

I believe there will be more of that coming up…​.

7.13 Javascript’s Illusion of Classes

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.

7.14 Javascript Classes

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:

proto1
rich and james has 3 properties of their own. enginesActive, numEngines, and startEngines.


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:

proto2

startEngine function is stored in the shared proto area.

Introducing classes

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.

7.15 Convert a Function to a Class

The changes are actually a lot more straightforward than I thought and I’m actually loving it.

proto3

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.

7.16 Working with JavaScript Class

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

Quiz

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.

static methods

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.

class rules

  • Class doesn’t get hoisted. Which means if you were going to do a call for that class, make sure its under it’s declaration.

  • You can only create new instances of the JavaScript class with the new keyword.

7.17 Super and Extends

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.

7.18 Extending Classes from ES5 to ES6

This section is just explaining the difference between ES5 and ES6 when it comes to constructors and their prototypes.

proto4

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);

7.19 Working with JavaScript Subclasses

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.

Quiz 1 of 2

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.


Quiz 2 of 2

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()

7.20 Quiz: Building Classes and Subclasses (2 - 3)

  1. Here we have to create our own subclass Bicycle for the Vehicle class.

  2. 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);
    }

}

7.21 Lesson 2 Summary

Here is a recap of what we’ve learned in Lesson 2:

  • The new way to write functions with ⇒ (Arrow Functions)

  • The new and much easier way to write default values for functions.

  • Javascript classes and subClasses that is simulated through functions.