chore(curriculum): add JavaScript classes transcript (#58617)

Co-authored-by: Naomi <accounts+github@nhcarrigan.com>
Co-authored-by: Farhan Hasin Chowdhury <shovik.is.here@gmail.com>
This commit is contained in:
Zaira
2025-02-13 11:39:50 -05:00
committed by GitHub
co-authored by Naomi Farhan Hasin Chowdhury
parent 93341f265f
commit 3f41523142
4 changed files with 527 additions and 0 deletions
@@ -10,6 +10,122 @@ dashedName: what-are-classes-and-how-do-they-work-in-javascript
Watch the video lecture and answer the questions below.
# --transcript--
What are classes, and how do they work in JavaScript?
Let's learn about classes in JavaScript.
In modern JavaScript, classes are like blueprints that you can define in code for creating multiple objects of the same kind.
For example, if you're modeling an inventory system, you'll need to create multiple objects per type of product.
Each individual product will have its own properties and actions but products of the same kind can be created from the same "blueprint". That's what classes are used for.
Classes can be defined as either a class expression or class declaration.
Here is the basic syntax for a class declaration:
```js
class MyClassName {
// Class Methods
constructor() { ... }
method1() { ... }
method2() { ... }
...
}
```
You start by writing the `class` keyword followed by the name of the class. When naming classes, you should use the `PascalCase` naming convention instead of `camelCase`.
The content inside the curly braces is known as the class body. This is where the constructor and methods will go.
The constructor is a special method that gets called automatically when a new object is created from the class. It is typically used to initialize the properties of the object.
In this example, you can see a `Dog` class with a constructor.
```js
class Dog {
constructor(name) {
this.name = name;
}
}
```
The `this` keyword is used here to refer to the current instance of the `Dog` class, allowing you to assign the `name` property to the object being created. You will learn more about the `this` keyword in a future lecture.
Below the constructor, you can have what are called methods. Methods are functions defined inside a class that perform actions or operations. They are used to define behaviors that instances of the class can perform.
Here is an example of adding a method called `bark` to the `Dog` class.
```js
class Dog {
constructor(name) {
this.name = name;
}
bark() {
console.log(`${this.name} says woof!`);
}
}
```
When the `bark` method gets called the message will be logged to the console with the actual name that was passed into it. If you create a `Dog` instance with the name `"Buddy"`, calling the `bark()` method on that instance will print `"Buddy says woof!"` to the console.
Once you have your class defined, you can create an instance of the class with the `new` keyword, the name of the class, and its arguments.
In this example, we create a new `Dog` instance with the name `Gino` and then we assign it to the variable `dog`.
```js
const dog = new Dog("Gino");
```
When you write `new Dog("Gino")` in your code, the new object is created and the constructor is called automatically with the given arguments.
You can then access this property using the dot notation, like you can see in the following line of code:
```js
console.log(dog.name);
```
This will log the value of the `name` property of this particular instance:
```js
Gino
```
You can also call methods. In this example, we are calling the `bark()` method on the `dog` instance.
```js
dog.bark();
```
This will log the following message to the console:
```js
Gino says woof!
```
As mentioned earlier, you can also define classes as a class expression. This is where the class is anonymous and assigned to a variable.
Here is what the earlier example looks like as a class expression:
```js
const Dog = class {
constructor(name) {
this.name = name;
}
bark() {
console.log(`${this.name} says woof!`);
}
};
```
Most of the time, you'll use class declarations, but understanding class expressions is also valuable, as they can offer more flexibility, especially in dynamic programming situations.
By using classes and understanding their basic syntax, you can create reusable code, organize it into logical units, and promote code modularity.
# --questions--
## --text--
@@ -10,6 +10,89 @@ dashedName: how-does-the-this-keyword-work
Watch the lecture video and answer the questions below.
# --transcript--
How does the `this` keyword work?
Let's learn about the `this` keyword. You learned that classes are like blueprints that you can use to create objects.
These blueprints need a general way to refer to the specific object that is being created, accessed, or modified within the code. That's exactly what the `this` keyword is used for. It refers to the context where the code is supposed to run. If you use it within a method, the value of `this` will be a reference to the object associated to that method. This way, you can access the properties and methods of the object within the class and reuse the method on different objects.
For example, here we have a `Dessert` class. This time, we're defining a `hasPeanuts` property.
```js
class Dessert {
constructor(hasPeanuts) {
this.hasPeanuts = hasPeanuts;
}
}
```
Notice that we're using the `this` keyword within the constructor. Remember that the constructor is called automatically when a new object of the class is created.
The `this` keyword is telling the program that `hasPeanuts` should be a property of the object that is currently being created.
The right-hand side of the assignment statement is assigning the value of the `hasPeanuts` parameter to the `hasPeanuts` property of the new object.
```js
this.hasPeanuts = hasPeanuts;
```
That's in the context of the constructor but you can also use the `this` keyword within other methods.
This is our `Dessert` class with a few changes. Now we have two properties: `name` and `price`.
```js
class Dessert {
constructor(name, price) {
this.name = name;
this.price = price;
}
showPrice() {
console.log(`The price of ${this.name} is $${this.price}.`);
}
}
```
We also have a new `showPrice` method. In this method, we print a descriptive message to the console with the name and the price of the dessert object.
Notice how we're using the `this` keyword to access the properties of the object within the `showPrice` method.
What value will the `this` keyword have in the context of this method? It will refer to the object on which the method is being called. In this case, we're creating a new Dessert instance with the name `“Brownie”` and the price `$5.99`:
```js
const brownie = new Dessert("Brownie", 5.99);
```
If we call the `.showPrice()` method on this object:
```js
brownie.showPrice();
```
Here is the output:
```js
The price of Brownie is $5.99.
```
The name and price of the current object (`brownie`) are replaced in the string.
This is all thanks to the `this` keyword, which gives you a general way to refer to the current object within the class. This allows you to reuse the method on different objects.
This is in the context of object methods but the `this` keyword will also have a value in standalone functions and arrow functions.
Its value within a standalone function typically refers to the global object (in non-strict mode) or `undefined` (in strict mode).
The value of the `this` keyword is a bit different in arrow functions. Arrow functions inherit the value of `this` from the enclosing scope where they are defined. They don't create their own `this` binding. That means that the value of `this` depends on the context where the arrow function is defined, not where or how the arrow function is called. This makes arrow functions helpful for callbacks or for preserving context.
However, because of this, the value of `this` will not refer to the current object in object methods, so this is something that you should keep in mind when working with arrow functions.
The same applies to arrow functions defined within other functions. They will inherit the value of `this` from their parent scope.
The `this` keyword is a powerful tool for accessing and manipulating objects. Understanding how it works is essential for mastering object-oriented programming in JavaScript.
# --questions--
## --text--
@@ -10,6 +10,154 @@ dashedName: what-is-class-inheritance-and-how-does-it-work
Watch the lecture video and answer the questions below.
# --transcript--
What is class inheritance, and how does it work?
Let's learn about inheritance and how it works in JavaScript.
In programming, inheritance allows you to define classes that inherit properties and methods from other classes.
For example, a `Car` is a type of `Vehicle`, so you could define a `Vehicle` class with the most general properties and methods that are common to all types of vehicles and then define a `Car` class that inherits the properties and methods of the `Vehicle` class.
This "is a" relationship is characteristic of inheritance. In this example, `Car` is a more specialized form of `Vehicle`.
There are two main concepts that you should know about to start working with inheritance: parent class and child class.
A parent class is a class that acts like a blueprint for other classes. It defines properties and methods that are inherited by other classes.
A child class is a class that inherits the properties and methods of another class. Child classes can also extend the functionality of their parent classes by adding new properties and methods.
In our previous example, `Vehicle` would be the parent class of the `Car` class while the `Car` class would be the child class of `Vehicle`.
A parent class can have multiple child classes.
In JavaScript, we use the `extends` keyword to implement inheritance. This keyword indicates that a class is the child class of another class.
In this example, in which we only have the first lines of the class definitions, you can see that the `Car` class extends the `Vehicle` class, so `Car` inherits from `Vehicle`.
```js
class Vehicle {
// Implementation of Vehicle...
}
class Car extends Vehicle {
// Implementation of Car...
}
```
Let's say that the `Vehicle` class has two properties: `brand` and `year`. You can see this in the updated code.
`Car` has a method called `honk`. However, notice that the `Car` class doesn't have its own constructor. Let's see if it does inherit the properties.
```js
class Vehicle {
constructor(brand, year) {
this.brand = brand;
this.year = year;
}
}
class Car extends Vehicle {
honk() {
console.log("Honk! Honk!");
}
}
```
To define an instance of `Car`, you'll need to pass two arguments: `brand` and `year`. In this case, the brand is `freeCodeCamp Motors` and the year is `2019`.
```js
let myCar = new Car("freeCodeCamp Motors", 2019);
```
If you try to access these properties and call the method using dot notation:
```js
console.log(myCar.brand);
console.log(myCar.year);
myCar.honk();
```
Here is the output:
```js
freeCodeCamp Motors
2019
Honk! Honk!
```
Indeed, the output is correct, so these properties and method are defined in the `Car` instance and you just saved yourself a lot of code repetition by inheriting these properties from the `Vehicle` class.
In this example, the child class didn't have any additional properties. That's why the class didn't have a constructor, only a method.
If you do need to add additional properties, you'll need to define a constructor.
Let's see an example.
```js
class Vehicle {
constructor(brand, year) {
this.brand = brand;
this.year = year;
}
}
class Car extends Vehicle {
constructor(brand, year, numDoors) {
super(brand, year);
this.numDoors = numDoors;
}
}
```
This time, we'll add a `numDoors` property to the `Car` subclass.
You can see that now this class has a constructor in the updated code. Within the constructor, there's a call to `super()`, passing the arguments `brand` and `year`.
`super()` invokes the constructor of the superclass, so by using `super(brand, year)` you will essentially be defining the properties of the superclass in the subclass. This is another terminology you can use- superclass is the parent class and the subclass is the child class.
Then, `this.numDoors = numDoors` line defines a new property that belongs exclusively to the `Car` class, the number of doors (`numDoors`).
This is a way to extend the `Vehicle` class, adding a property that is exclusive to `Car` instances.
That's is an example of extensibility, one of the fundamental advantages of inheritance.
Now, if you create an instance of the `Car` class, you'll see that it has the three properties: `brand`, `year`, and `numDoors`. You'll also need to pass the necessary arguments when you create the instance.
```js
let myCar = new Car("freeCodeCamp Motors", 2019, 4);
```
If you print the values of these properties with `console.log()`:
```js
console.log(myCar.brand);
console.log(myCar.year);
console.log(myCar.numDoors);
```
This is the output:
```js
freeCodeCamp Motors
2019
4
```
The main advantages of inheritance are code reusability, modularity, extensibility, and improved code structure.
By implementing a hierarchy, you can reuse code that you already wrote for a parent class in the child class, avoiding repetition.
Inheritance also promotes modularity by breaking down complex systems into simpler components in the hierarchy.
Also, being able to extend the functionality of the parent class makes it easier to adapt to changing requirements and add new features later on in the development process.
Finally, the hierarchical structure can make your code easier to understand and maintain.
Those are the fundamentals of inheritance. By understanding how inheritance works, you can design well-structured, maintainable, and extensible object-oriented programs.
# --questions--
## --text--
@@ -10,6 +10,186 @@ dashedName: what-are-static-properties-and-methods-in-classes
Watch the lecture video and answer the questions below.
# --transcript--
What are static properties and methods in classes?
Let's learn about static properties and methods.
Static properties and methods belong to the class itself, not to the individual instances of the class. You can access them directly on the class name without creating an instance of the class. They are defined within classes to encapsulate related functionality.
You can define a static method by writing the `static` keyword before the name of the method.
```js
class MyClass {
static staticMethod() { ... }
}
```
Then, you can call the static method on the class directly, using dot notation and passing any necessary arguments:
```js
MyClass.staticMethod();
```
Notice that you are able to call the method without creating an instance of the class. That's one of the key characteristics of static methods.
Here's an example. Let's say that we are creating a movies application and we want to be able to compare movies based on their rating.
We could consider this comparison method as a higher level method that is not specific to any movie:
```js
if (movieA.rating < movieB.rating) {
console.log(`${movieB.title} has a higher rating.`);
}
```
It's like a more general method related to the `Movie` class.
For readability and maintainability purposes, it would be helpful to define it within the `Movie` class to keep all related methods relatively close to each other.
Therefore, this is a perfect candidate for a static method. You can see it here, just below the constructor:
```js
class Movie {
constructor(title, rating) {
this.title = title;
this.rating = rating;
}
static compareMovies(movieA, movieB) {
if (movieA.rating > movieB.rating) {
console.log(`${movieA.title} has a higher rating.`);
} else if (movieA.rating < movieB.rating) {
console.log(`${movieB.title} has a higher rating.`);
} else {
console.log("These movies have the same rating.");
}
}
}
```
The static method is defined with the `static` keyword and it's called `compareMovies`. It has two parameters: `movieA` and `movieB`. These will be instances of the `Movie` class.
We will compare them based on their rating, on a range from `0` to `100`. This logic is implemented with a conditional and it will print an appropriate message based on which movie has a higher rating.
Once the method has been defined, you can call it on the class. But first, you need to have the arguments ready and defined in your program.
In this case, the method takes two movie instances as arguments, so we define these instances here:
```js
let movieA = new Movie("Movie A", 80);
let movieB = new Movie("Movie B", 45);
```
You can see that `movieA` has a higher rating than `movieB`. Let's see the output of this method.
To call the method, you just need to use dot notation on the class itself.
You write the name of the class (`Movie`), followed by a dot, and then the name of the static method (`compareMovies`).
Then, you pass the arguments within parentheses. In this case, they are the two movie instances that the method requires.
```js
Movie.compareMovies(movieA, movieB);
```
This is the output:
```js
Movie A has a higher rating.
```
Static methods are also helpful for implementing "factory" methods. A factory method is a method that you define in addition to the constructor to create objects based on specific criteria.
Here's an example with a `Pizza` class. The static method `createMargherita` is a factory method that you can call to create a Margherita pizza instance with its type and price already set.
```js
class Pizza {
constructor(type, price) {
this.type = type;
this.price = price;
}
static createMargherita() {
return new this("Margherita", 6.99);
}
}
```
This also brings up something very important about static methods.
The value of the `this` keyword in static methods is the class itself, since the static method belongs to the class.
That's why we can use `this` to create a new instance of the `Pizza` class.
If you call this method on the `Pizza` class itself and assign the returned instance to a variable, like in this example:
```js
let myPizza = Pizza.createMargherita();
```
You can use it wherever you need to in your code. For example, you can print it to the console:
```js
console.log(myPizza);
```
This is the output:
```js
Pizza { type: 'Margherita', price: 6.99 }
```
You can also use dot notation to call its methods and access its properties, like this:
```js
console.log(myPizza.type);
```
This is the output:
```js
Margherita
```
In addition to methods, you can also define static properties with the `static` keyword.
In this example, we have a static `numberOfPizzasSold` property.
```js
class Pizza {
static numberOfPizzasSold = 0;
constructor(type) {
this.type = type;
Pizza.numberOfPizzasSold++;
}
}
```
It's static because it doesn't belong to any particular pizza instance, it belongs to the class itself.
It has an initial value of `0` and it's updated every time a new instance is created.
If you create two pizza instances, the value will be updated twice:
```js
let pizza1 = new Pizza("Margherita");
let pizza2 = new Pizza("Neapolitan");
```
To access the value of a static property, you just need to use dot notation on the class itself, since the property belongs to the class.
```js
console.log(Pizza.numberOfPizzasSold);
```
In this case, the output is `2` because two pizzas were sold.
These are the fundamentals of static properties and methods in JavaScript. Understanding static members is essential for creating reusable and efficient classes.
# --questions--
## --text--