Intermediate JavaScript Basics - Classes to Modules
1. Intro to Classes
//Example: Template for dog behaviourclassDog {constructor(name) {this._name = name;this._behavior =0; }getname() {returnthis._name; }getbehavior() {returnthis._behavior; } incrementBehavior() {this._behavior ++; }}consthalley=newDog('Halley');console.log(halley.name); // Print name value to consoleconsole.log(halley.behavior); // Print behavior value to consolehalley.incrementBehavior(); // Add one to behaviorconsole.log(halley.name); // Print name value to consoleconsole.log(halley.behavior); // Print behavior value to console
you created a class called Dog, and used it to produce a Dog object.
there are similarities between class and object syntax, but JavaScript calls the constructor() method every time it creates a new instance of a class.
Dog is the name of our class. By convention, we capitalize and CamelCase class names.
JavaScript will invoke the constructor() method every time we create a new instance of our Dog class.
This constructor() method accepts one argument, name.
Inside of the constructor() method, we use the this keyword. In the context of a class, this refers to an instance of that class. In the Dog class, we use this to set the value of the Dog instance’s name property to the name argument.
Under this.name, we create a property called behavior, which will keep track of the number of times a dog misbehaves. The behavior property is always initialized to zero.
2. Instances
Now, we’re ready to create class instances. An instance is an object that contains the property names and methods of a class, but with unique property values.
classDog {constructor(name) {this.name = name;this.behavior =0; } }consthalley=newDog('Halley'); // Create new Dog instanceconsole.log(halley.name); // Log the name value saved to halley // Output: 'Halley'
Below our Dog class, we use the new keyword to create an instance of our Dog class.
store the instance in a variable halley that will store an instance of our Dog class.
We use the new keyword to generate a new instance of the Dog class. The new keyword calls the constructor(), runs the code inside of it, and then returns the new instance.
We pass the 'Halley' string to the Dog constructor, which sets the name property to 'Halley'.
Finally, we log the value saved to the name key in our halley object, which logs 'Halley' to the console.
In the example above, we add getter methods for name and behavior. Notice, we also prepended our property names with underscores (_name and _behavior), which indicate these properties should not be accessed directly. Under the getters, we add a method named .incrementBehavior(). When you call .incrementBehavior() on a Dog instance, it adds 1 to the _behavior property. Between each of our methods, we did not include commas.
The syntax for calling methods and getters on an instance is the same as calling them on an object — append the instance with a period, then the property or method name. For methods, you must also include opening and closing parentheses. instance.method()
let nikko =newDog('Nikko'); // Create dog named Nikkonikko.incrementBehavior(); // Add 1 to nikko instance's behaviorconsole.log(surgeonRomero.name)surgeonRomero.takeVacationDays(3) //calling the method console.log(surgeonRomero.remainingVacationDays)
4. Inheritance
New keywords: extends and super
MUST USE 'SUPER' before 'this'
classAnimal {constructor(name) {this._name = name;this._behavior =0; }getname() {returnthis._name; }getbehavior() {returnthis._behavior; }incrementBehavior() {this._behavior++; }} // extension inheritanceclassCatextendsAnimal { // makes methods of parent avail constructor(name, usesLitter) {super(name); // calls constructor of parent class this._usesLitter = usesLitter; }}
The extends keyword makes the methods of the animal class available inside the cat class.
The constructor, called when you create a new Cat object, accepts two arguments, name and usesLitter.
The super keyword calls the constructor of the parent class. In this case, super(name) passes the name argument of the Cat class to the constructor of the Animal class. When the Animal constructor runs, it sets this._name = name; for new Cat instances.
_usesLitter is a new property that is unique to the Cat class, so we set it in the Cat constructor.
classHospitalEmployee {constructor(name) {this._name = name;this._remainingVacationDays =20; }getname() {returnthis._name; }getremainingVacationDays() {returnthis._remainingVacationDays; } //method to update leavetakeVacationDays(daysOff) {this._remainingVacationDays -= daysOff; }}// child class NurseclassNurseextendsHospitalEmployee {constructor(name, certifications) {super(name);this._certifications = certifications; } getcertifications (){returnthis._certifications; } //method to update certsaddCertification(newCertification){this._certifications.push(newCertification); } //push new cert to append to cert array}// call methodsconstnurseOlynyk=newNurse('Olynyk', ['Trauma','Pediatrics']);nurseOlynyk.takeVacationDays(5);console.log(nurseOlynyk.remainingVacationDays);nurseOlynyk.addCertification('Genetics');console.log(nurseOlynyk.certifications)
5. Static Methods
Sometimes you will want a class to have methods that aren’t available in individual instances, but that you can call directly from the class. Because of the static keyword, we can only access .generateName() by appending it to the Animal class.
The static keyword defines a static method or property for a class, or a class static initialization block (see the link for more information about this usage). Neither static methods nor static properties can be called on instances of the class. Instead, they're called on the class itself.
Static methods are often utility functions, such as functions to create or clone objects, whereas static properties are useful for caches, fixed-configuration, or any other data you don't need to be replicated across instances.
We call the .generateName() method with the following syntax:
You cannot access the .generateName() method from instances of the Animal class or instances of its subclasses. The example above will result in an error, because you cannot call static methods (.generateName()) on an instance (tyson).
Case 3 : Password Generator for Hospital Employees using Static Method
A runtime environment is where your program will be executed. JavaScript code may be executed in one of two runtime environments:
a browser’s runtime environment
the Node runtime environment
In each of these environments, different data values and functions are available, and these differences help distinguish front-end applications from back-end applications.
Front-end JavaScript applications are executed in a browser’s runtime environment and have access to the window object.
Back-end JavaScript applications are executed in the Node runtime environment and have access to the file system, databases, and networks attached to the server.
Modules are reusable pieces of code in a file that can be exported and then imported for use in another file. A modular program is one whose components can be separated, used individually, and recombined to create a complex system.
# Module Implementation
In JavaScript, there are two runtime environments and each has a preferred module implementation:
The Node runtime environment and the module.exports and require() syntax.
The browser’s runtime environment and the ES6import/export syntax.
How to take input arguments
process.argv[x] takes the indexed input of the cmd interface
celsiusInput is assigned process.argv[2]. When a program is executed in the Node environment, process.argv is an array holding the arguments provided. In this case, it looks like ['node', 'celsius-to-fahrenheit.js', '100']. So, process.argv[2] returns 100.
/* $ node celsius-to-fahrenheit.js 100 // THIS IS THE CMD INPUT100 degrees Celsius = 212 degrees Fahrenheitcelsius-to-fahrenheit.js */functioncelsiusToFahrenheit(celsius) {return celsius * (9/5) +32;}constcelsiusInput=process.argv[2]; // Get the 3rd input from the argument listconstfahrenheitValue=celsiusToFahrenheit(celsiusInput);console.log(`${celsiusInput} degrees Celsius = ${fahrenheitValue} degrees Fahrenheit`);
# Module.exports
To create a module, you simply have to create a new file where the functions can be declared. Then, to make these functions available to other files, add them as properties to the built-in module.exports object
// 1. Define your function to exportfunctioncelsiusToFahrenheit(celsius) {return celsius * (9/5) +32;}// 2. First method of exporting function - call "module.exports.function_name"module.exports.celsiusToFahrenheit = celsiusToFahrenheit;// 3. Second method is to define function as module.exports.variable_namemodule.exports.fahrenheitToCelsius=function(fahrenheit) {return (fahrenheit -32) * (5/9);};
# Require
The require() function accepts a string as an argument. That string provides the file path to the module you would like to import. When you use require(), the entire module.exports object is returned and stored in the variable converters. This means that both the .celsiusToFahrenheit() and .fahrenheitToCelsius() methods can be used in this program!
/* water-limits.js */const converters = require('./converters.js'); // import module, ./ represents converters.js is in the same directory
constfreezingPointC=0;constboilingPointC=100;constfreezingPointF=converters.celsiusToFahrenheit(freezingPointC);constboilingPointF=converters.celsiusToFahrenheit(boilingPointC);console.log(`The freezing point of water in Fahrenheit is ${freezingPointF}`);console.log(`The boiling point of water in Fahrenheit is ${boilingPointF}`);//TO IMPORT ONLY A SPECIFIC PART OF THE OBJECT (reduce importing uneccassary modules)const { celsiusToFahrenheit } =require('./converters.js');constcelsiusInput=process.argv[2]; constfahrenheitValue=celsiusToFahrenheit(input);console.log(`${celsiusInput} degrees Celsius = ${fahrenheitValue} degrees Fahrenheit`);
Coding Challenges - Modules Concept Review 1
// shape-area.jsconstPI=Math.PI;// 1. Define and export circleArea() and squareArea() belowfunctioncircleArea(radiusLength){returnPI*radiusLength**2;}functionsquareArea(sideLength){return sideLength**2;}module.exports.circleArea = circleAreamodule.exports.squareArea = squareArea// 2. IMPORT MODULE from above shape-area.js/* app.js */constradius=5;constsideLength=10;// Option 1: import the entire shape-area.js module here.constareaFunctions=require('./shape-area.js');// Option 2: import circleArea and squareArea with object destructuringconst { circleArea,squareArea } =require("./shape-area.js")// use the imported .circleArea() and .squareArea() methods hereconstareaOfCircle=circleArea(radius);constareaOfSquare=squareArea(sideLength);console.log(areaOfCircle);console.log(areaOfSquare);
7. Review of Modules - Import & Export for ES6
Exporting in 2 ways:
// METHOD 1 : LIST ALL TOGETHERexport { toggleHiddenElement, changeToFunkyColor };//METHOD 2 : CALL EXPORT BEFORE DECLARING VARIABLEexportconsttoggleHiddenElement= (domElement) => {}