Open CheatSheet Back To List Next Tutorial

Classes

Intro

  • This tutorial covers JavaScript Classes.

  • It is recommended that you follow along with each section below. Paste or type the code into your own JavaScript file and view the variable or expression values either with console.logs or using the VS Code Debug sidebar. 

  • The example code for the entire tutorial series is at github.com/LearnByCheating/javascript-tutorial. There is a separate file or folder for each tutorial, including the To-Do List example project. The Readme file has instructions on how to run the code.


1. Class declarations

  • If you want to create a single unique object, use an object literal.
  • If you want to create multiple objects that have the same properties and methods, use a class. 

  • Like most popular programming languages, JavaScript is object oriented. But unlike the others, JavaScript uses prototypes to create objects, instead of classes. 
  • However, in the 2015 ES6 release a class syntax was added to JavaScript. This gives it a similar look and feel to to class-based programming languages. 
  • Behind the scenes JavaScript still uses prototypes, but class syntax enforces class-like behavior. 
  • A JavaScript class is a special type of function, called a constructor function, that generates new objects. 
    • It is a template that defines the properties and methods that all instances of this class will have.

Format:
class ClassName {
    constructor(prop1, prop2) {
      this.prop1 = prop1;
      this.prop2 = prop2;
    }
  }
  const instance1 = new ClassName(val1, val2);

  • To create a class, declare it with the class keyword followed by the class name. By convention, the class name is capitalized and singular. Put multiple word names in UpperCamelCase.
  • Then add a function named constructor, with parameters for the object property values.
  • The this keyword refers to the instance object you are creating. The constructor chains each property name to the object being created and assigns it to the parameter value passed in. 
  • To instantiate an object: 
    • Call the class with the new operator. 
    • Pass in the property values as arguments. 
    • The class will return a new object. 
    • Assign the returned object to a variable.

Author example:
class Author {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }
}
const author1 = new Author('Joey', 32);

  • The above example creates an Author class.
  • The constructor function has parameters for name and age.
  • In the last line we instantiate a new object by calling the Author class with the new operator, passing in arguments 'Joey' and 32 for the name and age property values. We assign the new object to variable author1.

Book example:
class Book {  
  constructor(title, price, categories, author) {
    this.title = title;
    this.price = price;
    this.categories = categories;
    this.author = author;
  }
}
const book1 = new Book('Learn JavaScript', 19.95, ['education', 'tech'], author1);
const book2 = new Book('Learn Node.js', 23.95, ['education', 'tech'], author1);
const book3 = new Book('Learn Express', 25.95, ['education', 'tech'], author1);

  • Above is a Book class example with properties for title, price, categories and author. Property values can be any data type including arrays and objects.
  • Then we instantiate three book objects: book1, book2, and book3.


2. Instance properties

  • You can access property values by chaining the property name to the object.
let view = book1.title; // returns "Learn JavaScript"

  • You can also use bracket notation.
view = book1['price']; // returns 19.95

  • For properties that are objects, like author, chain the object to the property you want to access. book1.author.name gets the book author's name.
view = book1.author.name; // returns "Joey"

  • You can set property values with the equals assignment operator.
book1.price = 22.95;

  • Instance objects have an internal property called [[prototype]] that you cannot access in your code. JavaScript uses it to access instance methods attached to the prototype which can be applied to the object. 


3. Instance methods

  • Instance methods are functions that are applied to a specific instance of a class.

Format:
class ClassName {
    constructor(prop1, prop2) {
      this.prop1 = prop1;
      this.prop2 = prop2;
    }
    method1() { statements; };
    method2() { statements; };
} const instance1 = new ClassName(val1, val2); instance1.method1();

  • You don't put instance methods in the constructor function. You put them after the constructor. That way they are attached directly to the class, not the instance object. Unlike property values, methods do not change for individual objects of the class. So there is no need to store separate copies of the methods with each object. Instead they are attached to the class's prototype.
  • The syntax is a shortened syntax of a function expression. Just the method name, parentheses, then the method body: methodName() { statements; }
  • Use the keyword this to reference the current object. For example, this method adds 1 to the object's age value: addYear() { this.age += 1; }
  • Call the method by chaining it to an instance object: obj.methodName()

Author example:
class Author {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }
  addYear() { this.age += 1; };
  log() { return `${this.name} is ${this.age} years old.` };

}
const author1 = new Author('Joey R', 32);
author1.addYear();
let view = author1.log(); // returns Joey R is 32 years old.
view = (Object.getPrototypeOf(author1) === Author.prototype); // returns true

  • The above class has two instance methods.
  • AddYear adds 1 to the age property.
  • Log returns a string with information about the author.
  • We instantiate an Author object and assign it to variable author1.
  • Then call author1.add() which changes the age property value to 33.
  • Then call author1.log() which returns information about the author1 object.
  • On the last line we check if the prototype for author1 is Author.prototype, and confirm that it is.

Methods defined in the class but outside the constructor are attached to the class prototype object.

Object.getOwnPropertyNames(Author.prototype); // returns ['constructor', 'addYear', 'log']
  • The above statement gets the instance properties and methods on the Article.prototype object. 
  • It returns the two methods from our class: addYear and log.
  • The constructor property is a reference to the class (aka constructor function) that created it.
view = author1.constructor; // returns Author


[4:55 Video Timestamp]
Book example:
class Book {
  constructor(title, price, published = false) {
    this.title = title;
    this.price = price;
    this.published = published;
    this.publishDate = published ? (new Date).toDateString() : null;
  }
  publish() {
    this.published = true; 
    this.publishDate = (new Date).toDateString();
  }
}; const book1 = new Book('Learn JavaScript', 19.95); book1; // returns { title: 'Learn JavaScript', price: 19.95, published: false, publishDate: null } book1.publish(); book1; // returns { title: 'Learn JavaScript', price: 19.95, published: true, publishDate: currentDate }

  • The Book class example above has parameters for title, price, published. 
  • Default parameter: As with any function, you can use a default parameter. So if no value for published is passed in, we will use a default value of false.
  • The publishDate parameter is not passed in as an argument. Instead we're using a ternary conditional statement. If published is true it will use the current date, otherwise it will set the value to null.
  • Then we have an instance method called publish that when called sets the published value for this object to true, and sets publishDate to the current date.
  • Then we instantiate book1 with a title and price. Published is automatically set to false and publishDate to null.
  • Then we call the publish method on book1.
  • Now published is true and publishDate is populated.

Object.getOwnPropertyNames(Book.prototype); // returns ['constructor', 'publish']
  • The above statement gets the instance properties and methods on the Book.prototype object. It returns the publish method from our class, and 'constructor'.
  • The constructor property is a reference to the class (aka constructor function) that created it.
view = book1.constructor; // returns Book


4. Static properties and methods

  • Static properties and methods apply to the overall class not to a specific instance. 
    • They can also called class properties and methods.
  • They are called on the class itself, not an instance of the class. 
  • To declare a static property or method use the static operator.

Format:
class ClassName {
    constructor(prop1, prop2) {
      this.prop1 = prop1;
      this.prop2 = prop2;
    }
    static propName = val;
    static methodName() { statements; }
  }

Example:
class Author {
  constructor(name, age) {
    this.name = name;
    this.age = age;
    this.id = Author.count += 1;
  }
  addYear() { this.age += 1; };
  static count = 0;
  static about() {
    return 'The Author class has properties for id, name, and age.';
  }

}

  • In the Author class above, there are properties for name and age. This time there is an id property that is not passed in as an argument. Instead we are get the count property from the class, and add 1 to it.
  • There is an instance method, addYear, that adds 1 to an object's age.
  • We also have a static property and a static method.
  • The static property count is set to 0: static count = 0
    • In the constructor, every time a new object is instantiated it adds 1 to Author.count, and sets its id property to that value: this.id = Author.count += 1
  • The about static method returns a string with general information about the class.

Create some objects:
const author1 = new Author('Joey', 32);
const author2 = new Author('Sheena', 28);
const author3 = new Author('Judy', 22);

Call the addYear instance method on author3. That increases the age property to 23.
author3.addYear();
  author3; // returns { name: 'Judy', age: 23 }

Call the about static method and the count static property:
let view = Author.about(); // returns "The Author class has properties for id, name, and age."
view = Author.count; // returns 3

Static properties and methods are attached to the Author class. The below statement gets all properties and methods attached directly to the Author class (not the prototype).
view = Object.getOwnPropertyNames(Author); // returns [length, name, prototype, about, and count]
  • Author class is a constructor function.
  • All functions have length and name properties. Length is the number of arguments expected when the function is called. We expect two arguments: name and age. 
    • Author.length; // returns 2
  • All constructor functions have a prototype property that holds the instance properties and methods available to objects created from the class. 
  • Count and about are the static property and method defined in the Author class.

[11:16 Video Timestamp]
Below are some statements to confirm the constructor, instance, and prototype relationships.

view = Object.getPrototypeOf(author3); // returns Author.prototype
view = Object.getPrototypeOf(author3) === Author.prototype; // returns true
view = typeof Author.prototype; // returns 'object'
view = author3.constructor; // returns class Author
view = author3.constructor === Author; // returns true
view = typeof Author; // returns 'function'
view = author3 instanceof Author; // returns true
view = Author instanceof Object; // returns true

They show that:
  • Author.prototype is the prototype of the author3 object. 
  • the prototype holds instance properties and methods that can be applied to author3.
  • The Author class is the constructor function that created author3, so author3 is an instance of the Author class. 
  • The Author class is an instance of the Object constructor function. 


5. Inheritance

  • The last topic we will cover is inheritance.
  • A class can have a parent class that it inherits from. It can be used when two or more classes share some common properties or methods but also have their own unique properties or methods. You can have a parent class that holds the common properties, and child classes that hold the unique properties. The child classes inherit from the parent class.

Format:
class ChildClass extends ParentClass {
    constructor(prop1, prop2, prop3) {
    super(prop1, prop2);
    this.prop3 = prop3;
  }
} const instance1 = new ChildClass(val1, val2, val3);

  • In the class declaration you use the extends keyword followed by the name of the parent class.
  • In the constructor function declaration, as usual, you add parameters for each property value that gets passed in when instantiating an object.
  • For properties defined in the parent class, call the super method inside the constructor, with parameters for those properties.

  • Instantiate an object the usual way. Call the class name with the new operator, passing in the property values as arguments.

Example:
// Parent class
class Product {
  constructor(price, quantity) {
    this.price = price;
    this.quantity = quantity;
  }
}
// Child class
class Book extends Product {
  constructor(title, author, price, quantity) {
    super(price, quantity);
    this.title = title;
    this.author = author;
  }
}
const book1 = new Book('Learn JavaScript', 'Judy R', 19.95, 27);

  • In the above example there is a store with different types of products. All products have price and quantity properties. Product is the parent class.
  • One of types of products sold are books. Books have title and author properties. Book is the child class.
  • In the last line we instantiate a new book object by calling the Book class and passing in argument values for title, author, price, and quantity. 

The prototype chain
When you have inheritance, JavaScript is tracking the prototype chain behind the scenes. 
  • The below statements show the prototype chain.
view = Object.getPrototypeOf(book1) === Book.prototype; // returns true
  view = book1.constructor === Book; // returns true
view = book1 instanceof Book; // returns true view = Object.getPrototypeOf(Book.prototype) === Product.prototype; // true
view = Book instanceof Product; // returns true view = Object.getPrototypeOf(Product.prototype) === Object.prototype; // true
view = Product instanceof Object; // returns true view = Object.getPrototypeOf(Object.prototype) === null; // returns true

  • Book.prototype is book1's prototype object. It holds the properties and methods that can be applied to the book1 object. 
  • The Book class is the constructor function that created the book1 object. So book1 is an instance of the Book class.
  • Product.prototype is the prototype of Book.prototype. Book is an instance of the Product class since Book inherits from Product.
  • Object.prototype is the prototype of Product.prototype, and Product is an instance of the Object class since all objects inherit from the Object class.
  • Object.prototype is at the top of the prototype chain. Its prototype is null. 

That concludes this tutorial on JavaScript classes.


Conclusion

The topics in this tutorial correspond with the JavaScript CheatSheet Classes category. Make sure you understand each topic so you can refer back to the CheatSheet when working on your own projects.

If you have the CheatSheet desktop app and downloaded the JavaScript CheatSheet, then go through the flashcards for this category to the point where you can answer them all in order and shuffled.
Open CheatSheet Back To List Next Tutorial