Classes and Inheritance
Overview and Objectives
This lab introduces the modern JavaScript class syntax and demonstrates how to define classes, use getters/setters, and implement inheritance using the extends
keyword. Learners build a base class and a subclass, test static properties, and explore method overriding to understand object-oriented programming in JavaScript. By the end of this lab, learners will be able to:
- Declare classes in JavaScript using the
class
syntax with constructors to initialize object state. - Define instance properties and methods within a class.
- Implement getters and setters to control access to object properties.
- Create subclasses using the
extends
keyword to establish inheritance. - Utilize the
super
constructor call to initialize base class state in a subclass. - Define and use static properties or methods that belong to the class itself.
- Understand the relationship between classes and traditional constructor functions/prototypes.
Tasks and Instructions
You will create a small class hierarchy to model a product in an inventory and demonstrate class features like inheritance, getters/setters, and static members.
Task 1: Define a Base Class
- Create a class
Product
. Give it a constructor that accepts at least two parameters, for examplename
andprice
, and initializes those as properties of the instance (this.name
,this.price
).- Inside the class, define a method
describe()
that returns a string describing the product, e.g.,"<name> costs $<price>"
. (Usethis.name
andthis.price
in the string.) - Also, add a getter for the
price
property that simply returns the price, and a setter forprice
that ensures the new price is not negative (if a negative value is assigned, perhaps set it to 0 or throw an error). This will provide controlled access to the price property. - Test: After defining the class, create an instance of
Product
(for example,const prod1 = new Product("Laptop", 1200)
). Use thedescribe()
method and the price getter to verify they work (e.g., logprod1.describe()
andprod1.price
). Then try using the price setter (e.g.,prod1.price = -50
) and ensure it either prevents the change or handles it as you designed (e.g., sets to 0). Log the result to confirm the setter’s behavior.
- Inside the class, define a method
Task 2: Static Members
- Add a static property
count
to theProduct
class (using thestatic
keyword) and initialize it to 0. Each time the constructor is called (i.e., a new product is created), increment thisProduct.count
by 1. This will track how many products have been created.- Also add a static method (e.g.,
printCount()
) that logs or returns the total count of products. - Test: After creating a few Product instances (e.g., create
prod2 = new Product("Phone", 800)
etc.), callProduct.printCount()
(or accessProduct.count
) to verify that the count has incremented correctly and reflects the number of instances.
- Also add a static method (e.g.,
Task 3: Create a Subclass
- Define a class
Book
that extendsProduct
(useclass Book extends Product
). TheBook
class should have a constructor that takes at least the same parameters asProduct
(name and price) plus an additional one specific to books (for example,author
).- In the
Book
constructor, callsuper(name, price)
to initialize the inherited properties, then set the additional property (e.g.,this.author = author
). - Override the
describe()
method inBook
to include the author’s name in the description. For example, it could return a string like"<name> by <author> costs $<price>"
. Usesuper.describe()
as a starting point or build a new string includingthis.author
. - Test: Create an instance of
Book
(e.g.,const book1 = new Book("1984", 15, "George Orwell")
). Callbook1.describe()
and ensure it includes the book’s name, price, and author. Also test that inherited features work: for instance, use the inherited price getter or setter (book1.price
) and verify thatBook.count
(the static count) also reflects this new instance. Ensure that callingBook.printCount()
works and includes books in the count (because they are also Products).
- In the
Task 4: Using Class Instances
- Interact with your objects to demonstrate the class features. For example:
- Change the price of the
Book
instance using the price setter (e.g.,book1.price = 20
) and then get it via the getter to ensure the setter logic was applied (no negative prices, etc.). - Call the
describe()
method on both a Product instance and the Book instance to show the different outputs. - If you implemented another method or property, demonstrate it as well (for instance, if you added a method specific to Book).
- Also, try referencing the static count via the subclass (e.g.,
Book.count
should also reflect the total count, since static properties are inherited). You could callBook.printCount()
to confirm it works from the subclass perspective too.
- Change the price of the
Task 5: Classes vs Constructor Functions (conceptual)
- (No code needed for this part, but think about it or discuss in comments) Reflect on how the class syntax you used relates to the older way of creating objects using constructor functions and prototypes. For example, consider that the
Product
class could be implemented with a functionProduct(name, price)
and adding methods toProduct.prototype
. You do not need to write this out unless instructed, but understanding this connection solidifies that JavaScript classes are built on top of prototypes.
Submission Criteria
Via a GitHub repository, submit the following via Canvas:
- Submit the JavaScript code file
lab2.js
containing your class definitions and the test code that creates instances and demonstrates each requirement. Ensure your submission shows the outputs (via console.log or similar) for the tests described, so that each feature (constructor, method, getter/setter, static, inheritance) can be verified. - The code should run without errors in Node.js or a browser console. You should be able to create instances and call the class methods as described. If any part of a requirement is not implemented, include comments explaining what you expected to do, to possibly earn partial credit.
- Ensure that your class and subclass names are exactly as requested and that static members and methods can be accessed as described (on the class, not instances).
Grading Rubric
Criteria | Points |
---|---|
Product class definition: Class Product is correctly declared with a constructor that initializes name and price . | 8 points |
Product methods and properties: describe() method in Product works as specified, and getter/setter for price correctly control access (e.g., preventing negative values). | 8 points |
Static member usage: A static property (e.g., count ) is implemented and updated in the constructor, and a static method (or direct property access) correctly reports the count of instances. | 6 points |
Book subclass definition: Class Book extends Product correctly, with a constructor that calls super() and adds an author property. | 7 points |
Method overriding: The Book class overrides describe() (or adds a new method) to include book-specific information, and this method works correctly. | 7 points |
Inheritance behavior: Instances of Book inherit properties and methods from Product (e.g., price getter/setter, static count). Demonstrated by using Book instances and verifying they have expected functionality from both classes. | 6 points |
Testing and output: The submitted code creates instances of both classes and demonstrates all functionalities (method outputs, getter/setter, static count) via console logs or comments. The code runs without errors. | 8 points |
Total Points: 50 points
Partial credit is available. Even if not all class features are implemented, you will earn points for each correctly implemented part (as outlined in the rubric). For instance, if the base class works but the subclass has issues, you will still get credit for the base class implementation.