JavaScript Classes
Introduction
This page covers JavaScript class implementation, inheritance, getters, setters, how to define dynamic read-only properties and static methods. JavaScript classes are templates for JavaScript objects. Classes are part of ES6.
You must declare a class before using the class.
Hoisting isn't available with JavaScript classes.
This page loads an external JavaScript file
in the header, named Cats.js
.
<script async src="javascript/Cats.js"></script>
Classes
The following two, blue and red, boxes demonstrate use of a JavaScript class. Below the boxes, I posted the class implementation and box HTML markup. The markup demonstrates creating a new class with constructor parameters.
Each class displays some information about specific cats
and calls the Javascript operator typeof
, with this
as the operand.
As you can see a JavaScript class is considered type object
.
Class Implementation
Every class has a constructor which is called
when a new class is created.
The name of the constructor is always constructor()
.
Include constructor parameters that you want applied
when a new object of the class is created.
The Cat constructor
requires two strings.
Formal arguments are breed
and behavior
.
class Cat { /** * Cat constructor. * @param breed: string * @param behavior: string. * @return: a new Cat object. */ constructor(breed, behavior) { this.breed = breed; this.behavior = behavior; this.element = null; } /** * Compose a string with * the cat's breed and behavior. * @return string: cat's breed, behavior. */ showInfo() { let s = this.breed+','+this.behavior; return s.toString(); } /** * Compose a string with the typeof operator. * @return string: this type. */ showType() { let s = '<br />Type: ' + typeof this; return s.toString(); } /** * Show everything about this * cat in an HTML element. * @param string: ID of an HTML element. */ showInfoType(sId){ this.element = document.getElementById(sId); this.element.innerHTML = this.showInfo(); this.element.innerHTML += this.showType(); } }
Box HTML Markup
The markup for each clickable
box displays below.
Create a new Cat
.
Pass parameters to the constructor
each time code creates a new Cat
.
Call method showInfoType()
.
The only parameter is the value of
the box's id
.
Create a new class with, new
, the name of the class,
and any constructor parameters.
For example, below you'll see, c = new Cat('Siamese', Loud')
,
where Siamese
is the constructor's first parameter and
Loud
is the constructor's second parameter.
<div id="bBlue" class="box" onclick="var c = new Cat('Siamese','Loud'); c.showInfoType('bBlue');" style="background-color:blue;" > Click for Cat Info </div> <div id="bRed" class="box" onclick="var c = new Cat('Bombay','Fat'); c.showInfoType('bRed');" style="background-color:red;" > Click for Cat Info </div>
Inheritance
Inheritance helps us reuse the Cat
class constructor, methods and properties,
in a subclass called CatWild
.
Reusing code offers the ability
to write concise, legible script.
Let's implement CatWild
as
a subclass of Cat
.
I declared Cat
and CatWild
in the same file.
See Cats.js.
Tap a Wild Cat Button to see the results. Read Inheritance Code with comments below, for implementation details.
Inheritance Code
Notice CatWild
extends the Cat
class.
Class CatWild's
constructor calls Cat's
constructor with the keyword super(...)
.
Class CatWild
reuses
class Cat's showInfoType()
method, within CatWild's
showInfoTypeRegion()
method.
In other words, CatWild.showInfoTypeRegion()
calls Cat.showInfoType()
because they are the same object.
Therefore showInfoType()
from Cat
is a method of
the CatWild
class too.
The CatWild
constructor
extends the Cat
base,
or Cat
parent class. Therefore CatWild's
constructor
also includes the breed and behavior.
Then CatWild's
constructor calls super(breed, behavior)
.
The call to super(breed, behavior)
calls
the parent class, Cat's
constructor.
// CatWild inherits from Cat: class CatWild extends Cat { /** * Constructor calls Cat * constructor, with Cat * parameters. * The last parameter * is assigned to * CatWild property; region. * @param breed: string cat breed. * @param behavior: string cat behavior. * @param region: string cat territory. */ constructor(breed, behavior, region) { // Call parent, Cat, // class constructor. super(breed, behavior); this.region = region; } /** * Display every field. * @param sId: String id of * HTML element. */ showInfoTypeRegion(sId) { // The parent 'Cat' class // includes public methods // and elements. // You can access them in this // child class. this.showInfoType(sId); this.element.innerHTML += '
Region: '+this.region; } }
Wild Cat Box Markup
The HTML markup is essentially the
same as the Cat
box
markup, except create a new
CatWild
object, with a third
constructor parameter.
Also call method showInfoTypeRegion()
instead of showInfoType()
.
var c = new CatWild('Jaguar','Fast','South America'); c.showInfoTypeRegion('bG');
Getters and Setters
You can add getters and setters to any class. Getters and setters allow developers to retrieve and assign property values, through a type of method.
Advantages
Getter and setter methods allow developers to modify access to some properties. Use of setter methods allow developers to perform validation on values before assignment.
Read Only
Exclusion of setter methods on a class indicates the developer may not want assignment of a value to a property. However, at this time, developers can look at the code and assign a value directly to the property, as you'll see below.
CatHybrid Child Class
Here we'll add getters and setters to the
CatHybrid
class which
extends the Cat
class.
Hybrids either mix wild cats with
domesticated cats or different breeds
of domesticated cats. The breeder often
tries to cultivate a cat that
looks wild yet behaves like a domesticated
variety.
The CatHybrid
constructor
will extend just the Cat
base,
or parent class. Therefore its constructor
also includes the breed and behavior.
class CatHybrid extends Cat{...}
Extension
Note that CatHybrid
could extend CatWild
instead of Cat
.
Then the CatHybrid
constructor would call the CatWild's
constructor with super(...)
, and
every CatWild
required parameter.
Additionally every property and
method along the chain from
Cat > CatWild > CatHybrid
would be available to CatHybrid
.
Instead we'll create a simple
constructor that can pass along Cat constructor
parameters, breed, behavior
.
We added one new parameter named, wildtype
.
constructor(breed, behavior, wildtype){...}
Simple CatHybrid Display
The light aqua box creates a default new
CatHybrid
and gives it a few unique qualities.
The red box creates a new CatHybrid
,
provides some unique qualities, then creates
the read only property called personality
.
Property personality
was preassigned
the value Awesome
.
Tap a hybrid cat button.
Cat Hybrid Box Markup
The markup is similar to
the original Box HTML Markup,
except create a new CatHybrid()
.
Assign a value to the setter.
For example, see the Savannah cat's qualities:
c.qualities='16 Inches Tall from the Shoulder';
Call method showInfoTypeHybrid()
.
No Setter Method
This little example demonstrates two attempts to assign a value to a property which has a getter method but not a setter method.
The blue box tries to use the non-existent
getter method for oddity
,
to assign the value Wild Appearance
.
It doesn't succeed.
The pink box circumvents the setter
and simply assigns the value Wild Appearance
to the
property catOddity
.
Property catOddity
really has
nothing to protect it from invalid assignments.
Developers can use the setter method to suggest future developers use setter, rather than assigning values directly to a property. Setter use currently isn't enforced.
Developers can omit the getter method to suggest future developers avoid assigning values to a specific property. However, there currently may not exist a technique to avoid assignment of predeclared properties. Yet, as you'll see below, dynamically defined properties provide a level of protection.
Box Markup with Workaround
The blue box attempts to assign Wild Appearance
to the non existent getter property.
So it doesn't work.
c.oddity='Wild Appearance';
The pink box assigns Wild Appearance
directly to the Cat
object's property catOddity
and it does work.
c.catOddity='Wild Appearance';
The entire markup follows.
<div id="bB" class="box" style="background-color:blue;" onclick="var c = new CatHybrid('Ocicat','Spotted','Domestic Cat with Ocelot Appearance'); c.qualities='Spotted fur.'; c.oddity='Wild Appearance'; c.showInfoTypeHybrid('bB'); " title="Hybrid Cat Button" > Click: Attempt Assign Get Only <em>Oddity=Wild Appearance</em> </div> <div id="bY" class="box" onclick="var c = new CatHybrid('Oriental Shorthair','Siamese without Points','Domestic Siamese'); c.qualities='Foreign Appearance'; c.catOddity='Wild Appearance'; c.showInfoTypeHybrid('bY');" style="background-color:#ffaaaa; color:black;" title="Hybrid Cat Button" > Click: Workaround Assign Get Only <em>Oddity=Wild Appearance</em> </div>
Protect Class Properties
The pink box below, creates a read-only property named personality
then attempts to assign Playful
to replace personality's
default value of,
Awesome
. The assignment doesn't succeed.
The aqua box creates a writeable property named personality
then attempts to assign Playful
to replace personality's
default value of,
Awesome
. The assignment does succeed.
Protect Properties
From this example you can see that creating readable and writable properties dynamically works to protect class variables.
Getters and setters, in this version of JavaScript, could
be considered developer suggestions for clean code, yet
they're easy to work around.
Use defineProperty
to create read only properties,
as you'll see below.
Read Only or Writeable Properties
Create read only or write only properties,
in a class,
with the defineProperty
method. Pass this
as the first parameter,
the name of your property, in this case; personality
,
as your second parameter.
Provide a value, and writeable: false
for read only properties.
Apply writeable: true
for
read and write properties, as follows.
assignReadOnly(){ Object.defineProperty(this, "personality", { value: " Awesome", writable: false }); } assignWriteable(){ Object.defineProperty(this, "personality", { value: " Awesome", writable: true }); }
Cat Hybrid Class
See the entire CatHybrid
class with getter and setter methods,
plus methods to create dynamic
read only or writable properties.
Both CatHybrid
and CatWild
derive from class Cat
.
They extend class Cat
,
which allows each sub class to access
properties and methods in the super class, Cat
.
// CatHybrid's parent // class is Cat. class CatHybrid extends Cat{ /** * CatHybrid constructor. * @param breed: string cat breed. * @param behavior: string cat behavior. * @param wildtype: string wild cat base. */ class CatHybrid extends Cat{ constructor(breed, behavior, wildtype) { // Call parent, Cat, // class constructor. super(breed, behavior); this.wildtype = wildtype; } get qualities() { return this.catQualities; } set qualities(d) { this.catQualities = d; } // You can get // but cannot set // oddity. get oddity() { return this.catOddity; } assignReadOnly(){ Object.defineProperty(this, "personality", { value: " Awesome", writable: false }); } assignWriteable(){ Object.defineProperty(this, "personality", { value: " Awesome", writable: true }); } showInfoTypeHybrid(sId) { this.showInfoType(sId); this.element.innerHTML += '
Wild Cat: '+this.wildtype; if(this.oddity != null){ this.element.innerHTML += '
Oddity:'+this.oddity; } else{ this.element.innerHTML +="
Oddity was not assigned."; } if(this.personality != null){ this.element.innerHTML += '
Personality:'+this.personality; } else{ this.element.innerHTML +="
Personality was not assigned."; } if (this.catQualities != null){ this.element.innerHTML +='
Qualities: '+this.catQualities; } } static description() { let s = "A hybrid cat is a domestic feline crossbred with a wild cat." return s + " TypeOf: " + typeof CatHybrid; } }
Static Methods
Static methods allow developers to call a method, with the name of the class, rather than the name of the class object. That means you can not access any class object properties, unless those properties are passed through the static method's parameter list.
Add Static Method
Add a static method to the
CatHybrid
class, as you can
see above.
That method named, definition()
will always return the same information.
/** * Static method * prepend the method name * with the static keyword * */ static description() { let s = "A hybrid cat is a domestic feline crossbred with a wild cat." return s + " TypeOf: " + typeof CatHybrid; }
Call a Static Method
The CatHybrid typeof
operator
returns function
.
Previously calling typeof
on a new class object, returns object
.
Static Method Markup
Notice you call CatHybrid.description()
not c = new CatHybrid(..); c.description();
.
Call the class name, not the class object.
<div class="box" onclick="this.innerHTML = CatHybrid.description()" style="background-color:#0088ff;" > Click for Hybrid Cat Description. </div>
Entire JavaScript
You may see the entire JavaScript source code applied to this lesson at Cats.js. I added fewer comments to the source code, to minimize download time. I added more comments to this page, to clarify each feature.
Summary
This page covered JavaScript class implementation, inheritance, getters, setters, how to define dynamic read-only properties and static methods. JavaScript classes are templates for JavaScript objects. Classes are part of ES6.