Defining Classes in JavaScript0:29
Object-oriented programming is extremely popular in other languages like PHP, Java, and C++. It allows you to build applications with reusable and maintainable blocks of code. Modern JavaScript allows you to make use of classes so you can leverage the use of object-oriented programming. So the idea is to use a class to define the properties and functionality of a certain entity. So let's use the example of a Teacher and a Student within a school system, which is the example they have on the MDN documentation, which you can find here. So if we go into our code, I have this folder here for OOP, object-oriented programming,
the example they have on the MDN documentation, which you can find here. So if we go into our code, I have this folder here for OOP, object-oriented programming, and for the index.html, I am importing a Student and a Teacher. Now when you make use of classes, the common convention is to uppercase the first character. So in this case, Student and Teacher are both classes. So the first character is uppercase. So let's start with Student here. You can see the definition for a class of a Student and the properties for a Student are their name and the currentYear that they're in. So say for example, this was some sort of college.
are their name and the current year that they're in. So say for example, this was some sort of college. Now the constructor is a special method here, which allows us to construct an actual Student, which we'll take a look at in a second. The params for the constructor are a name and a year. And then we assign this name to whatever is passed in and this year to whatever is passed in as well. And then we have two methods on the Student. We have introduceSelf, which just console logs, hi, my name is, and whatever the person's name is, or whatever the student's name is.
We have introduceSelf, which just console logs, hi, my name is, and whatever the person's name is, or whatever the student's name is. And then we have doHomework, which just console logs doing homework. Now we also have a Teacher class, which is similar to the Student. So let's take a look at that. Again, we have a name and we have a teaches property. The constructor is pretty much the same except now it uses name and teaches and introduceSelf is the same and giveHomework is only specific to teachers. So again, a class is used to define all of the properties and functionality of a certain entity.
Creating Class Instances2:10
So again, a class is used to define all of the properties and functionality of a certain entity. So in this case, we have students and teachers. So now how do we actually make a student or make a teacher? So if you go into our index.html here, let's go into our script tag here, we have student and teacher being imported. So what we can do is create a new instance of the class, and we can create as many as we like. So to do that, we can make use of the new keyword. So let's start with teachers, the teachers here, we can define a new variable like we've
So to do that, we can make use of the new keyword. So let's start with teachers, the teachers here, we can define a new variable like we've been doing, let's say andre for the variable name. And we can use the new keyword here to make a new instance of a Teacher in this case. So we can say new Teacher. And remember, our Teacher class has this constructor. So we have to pass in a name and a teaches property to create a new instance of it. So let's do that. name is andre and say andre teaches math. Okay, so this is one actual instance of the Teacher class, we can create as many as we
Name is Andre and say Andre teaches math. Okay, so this is one actual instance of the Teacher class, we can create as many as we like. Let's create another one named Jeffrey, the name is Jeffrey. And Jeffrey teaches music. Okay. And we also have this introduceSelf method on both the Teacher and the Student. So we can call that as well. So we can say Andre.introduceSelf().
So we can say Andre dot introduce self. Okay. And we can do the same for Jeffrey. Okay, now if we save this, it should run in the browser here. And you can see the console logs for the introductions. So we can do the same thing for students as well. So how about we just duplicate all of this. Now it's students. Let's change their names. Let's say Bob is a new student.
Let's change their names. Let's say Bob is a new student. Her name is Bob. And the second parameter for the constructor for a student is the year they're in. So we change the subject to a year, say Bob is year one. So that's one student. Let's create one more. How about Sally is a new student. Let's actually put their name in here. And Sally is in year three.
Let's actually put their name in here. And Sally is in year three. And we can do introduceSelf as well. These methods live on the Student, they are duplicated, which we'll take a look at cleaning up in a second. But let's say Bob, introduceSelf and Sally, introduceSelf. And now this should run and it does. So again, these are actual instances of the class. So Andre and Jeffrey are instances of Teacher, and Bob and Sally are instances of Student. And you can have as many as you like.
Using Inheritance to Reduce Duplication4:43
So Andre and Jeffrey are instances of Teacher, and Bob and Sally are instances of Student. And you can have as many as you like. Now if you take a look at Student and Teacher, there is some duplication here. For example, the name is duplicated in Student and Teacher. And also introduceSelf is the same for Student and Teacher. So what we can do here is leverage one concept of object oriented programming, and that is inheritance. So the idea is to put the duplicated code in a parent class, and then Student and Teacher can extend that. Let me show you that quickly.
can extend that. Let me show you that quickly. So first, we have to think of a parent class for a Student and a Teacher. So Students and Teachers are both People. So we can define a new class named Person that has this duplicated code between the Student and the Teacher. So let's do that. Let's just duplicate Student. Let's name it Person. And let's change this to Person.
Let's name it person. And let's change this to person. And we'll just have the duplicated properties and methods within Student and Teacher. So name is duplicated, year is specific to Student. So let's get rid of that. For the constructor, we only have a name here. So let's get rid of year here. Okay, introduceSelf is the same for Student and Teacher. So we can leave that here and doHomework is only for Student. So let's get rid of this.
So we can leave that here and do homework is only for students. So let's get rid of this. So now we have a generic Person class. So let's see if we can make use of this to get rid of the duplicated code. So if I save this, it's going to our index.html, make sure to import Person as well. So we have to duplicate this, we have to put Person first, because Student and Teacher make use of it. Okay. And now within Student and Person, we can use the extends keyword to make use of the Person as well.
And now within Student and Person, we can use the extends keyword to make use of the Person as well. So let's say extends Person. And now Person has name. So we no longer need it in here. The constructor for a Student is the same, but the name property lives on the Person class. So what we can do here is say call the constructor on the Person class. And to do that, we can say super to call the constructor on the parent, in this case, the Person and pass in the name, introduce self lives on the Person.
And to do that, we can say parent::__construct to call the constructor on the parent, in this case, the Person and pass in the name, introduceSelf lives on the Person. So we can get rid of this, or I'll just comment it out for now. So that's our Student. Now, let's update our Teacher as well. Let's say extends Person, name is on the Person now. So let's comment that out. Let's do the same thing here with parent::$name. And let's comment out introduceSelf, since that's on the Person now. Okay.
Overriding Methods (Polymorphism)7:36
So say for our Student and our Teacher, we still want to introduce self here. And since it's not defined on the Student and Teacher, the one on the Person is being used. But if we wanted one specific to the Student and the Teacher, we can define the same method, which sort of overrides the one on the Person. And this is what's known as polymorphism. So let's go back to our Student here. Let's comment this back in. But let's update the introduceSelf method. And this one is specific to the Student.
But let's update the introduceSelf method. And this one is specific to the Student. Hi, my name is name, I am in here, let's say this here, okay. And now this method should be run only on Student instances. So let's save that for the Teacher. Let's do something similar. Hi, my name is name, let's say I teach this teaches. Okay. Okay. So now if I save that, let's take a look at our browser console.
you can check out the wordle workshop, where Jeffrey recreates wordle, and he makes use of classes and object oriented JavaScript to encapsulate the game logic. So for example, if you take a look at the source, you'll see that this one is the class for a specific tile within wordle. And you can see the class right here. So we have our properties, we have our constructor, and we have a bunch of methods, or maybe just one or two methods. Also, if you take a look at popular libraries, you can see classes being used there as well. For example, this is bootstrap. This is the alert component.
Importing and Exporting Modules9:49
So within index.html, all I'm doing is importing this main.js here. And you can see it's trying to call a function named greeting, but that doesn't seem to be defined anywhere. It's actually defined in this greeting.js here, but it doesn't look like this is being imported anywhere. So if we go into the browser, we do get greeting is not defined. So this should be an easy fix. We just have to make sure to import greeting before main.js. So if I do that here, let's import greeting. And now hopefully this should be fixed.
So if I do that here, let's import greeting. And now hopefully this should be fixed. So save that. Go back to the browser. And we do get greetings Andre. Now this is fine, but there are a few problems with this. One is that in order for main.js, so in order for this to make use of greeting, greeting has to be within the global scope. And it is. Now the problem is that when we're making use of it in main.js, we sort of don't know
And it is. Now the problem is that when we're making use of it in main.js, we sort of don't know where this greeting is coming from. We have to reference where it's being used within index.html. If there were multiple scripts here, we'd have to guess where it's coming from. So it's not entirely explicit. So that's what importing and exporting using ECMAScript modules solves. So let me get rid of this greeting.js here. We should have that error again. And we do.
Okay. Let's save this. And we should still have that error because we're not importing greeting.js anywhere. And we do. So now if we go to greeting.js, we want this function to be able to be imported from any file. So what we can do is, and there are several ways to do this. Let me just show you one way. We can say export default, and then the function definition, or this can be a variable as well.
We can say export, default, and then the function definition, or this can be a variable as well. And now we should be able to import this file. Let me just save this from any other file. So now within main.js, we can use the import syntax and you'll definitely use this when you're making use of modern JavaScript tools. Usually at the top, you'll have a bunch of imports. So we can say import the thing we're importing, in this case, the greeting from, and we give it the file path. So in this case, it's in the same folder.
it the file path. So in this case, it's in the same folder. So we can say ./greeting.js and let's see if this works. So if I save this back to the browser and you can see, we do get our console log. But now if you look at our main.js, it's more explicit where this greeting is coming from. And also within here, this function is no longer globally scoped, which is nice. You can also export multiple things. So if I had another function, let's just duplicate this. Let's say function goodbye and let's just say goodbye name instead of greetings. Now we can't use export default anymore because export default is only if you have one export.
Let's say function goodbye and let's just say goodbye name instead of greetings. Now we can't use export default anymore because export default is only if you have one export. So let's just get rid of the default keyword. Okay. So now we're exporting two things here, two functions, greeting and goodbye, but we have to import it differently now since it's no longer a default export. So let me save this. Go back to our main.js. We have to use this curly bracket syntax. So curly brackets, the first one is greeting.
We have to use this curly bracket syntax. So curly brackets, the first one is greeting. So now this should still work. And it does. But now we can also import the goodbye method or goodbye function. Okay. And we can make use of that as well. goodbye, Sally. Save that. And it does work.
Asynchronous JavaScript with Promises13:48
For example, making a request to a server, maybe accessing the user's camera or microphone using the browser APIs, or maybe asking a user to select a file. So with tasks like these, you usually want to make use of asynchronous JavaScript. If we don't make use of asynchronous JavaScript, then our code will be synchronous. So I have an example here. So say for example, this method getPostsFromServer was synchronous and say that server was really slow to respond, say 10 seconds. Now with synchronous code, we'd have to wait for the result of this in order for the rest of the code here to run. Now with asynchronous code, then we wouldn't have to wait.
of the code here to run. Now with asynchronous code, then we wouldn't have to wait. So if I just duplicate this, let's say asynchronous code. And if we did this asynchronously, even if the response took 10 seconds, the rest of this code here will continue to execute. And then when we do get a response from the server, the code within the asynchronous code will continue to run. So let me show you a quick example here. And the most common example is to make use of the fetch API, which allows you to make an HTTP request.
And the most common example is to make use of the fetch API, which allows you to make an HTTP request. So this is making use of what's called a Promise, which is one way to do asynchronous code. So let's say promise here, and we'll make use of fetch. So let's get rid of this. Let's say fetch. So we're fetching from another endpoint here. Actually, let me just paste the code in here, since we're not going into too much detail. So we're fetching from this endpoint, this endpoint just fetches a bunch of dummy posts,
Actually, let me just paste the code in here, since we're not going into too much detail. So we're fetching from this endpoint, this endpoint just fetches a bunch of dummy posts, and I'm putting a limit of three on it. Actually, let me just show you this in the browser. So if I go to the endpoint, you'll see we have a bunch of dummy data here for posts. So what we're doing here is making an HTTP request to this endpoint, waiting for the result. Again, pretend the server took 10 seconds to respond with asynchronous JavaScript, any code that we have underneath will still continue to run. So if I had code down here, it will still continue to run, even though this code took
code that we have underneath will still continue to run. So if I had code down here, it will still continue to run, even though this code took 10 seconds to respond. So with promises, we have a then method. And in this case, we're just grabbing the response and changing it to JSON data. And then after that's done, we're console.logging the actual response. And if there's an error, we use catch to catch that error. So in this case, we're just logging the error. So if I save this, let's see if we actually get that post data within our console.log. So this line right here.
So if I save this, let's see if we actually get that post data within our console log. So this line right here. So let me save that back to the browser, back to our actual app, which is this one here. Let's open up DevTools here. And you can see we get this array. And you can see we get the post data here. So again, this is happening asynchronously. And even if the server took 10 seconds to respond, any code underneath here will still continue to execute. So other code here will execute for asynchronous code.
continue to execute. So other code here will execute for asynchronous code. Let's say will execute for async code. And there's also alternative syntax for promises called async await. So it's basically the same thing as promises, but just a different syntax. So I'm just going to paste that code in async await, we define a function, and put the async keyword in front of it. And then we have to await the thing that takes some time to complete. So in this case, we're awaiting the fetch response, and then we're console.logging the actual results.
