The Section 2: Functions & Methods of my JavaScript Core Concepts Series is divided into 6 Parts:
Part 1 Functions
Part 2 Classes
Part 3 Methods
Part 4 Callback Methods
Part 5 Scope
Part 6 Hoisting
Classes
Part 1 What are Classes?
= Template for creating Objects
→ Record data using logic that works through the data
How are JavaScript classes created?
= They are created on Prototypes
→ And include some syntax & semantics that are not shared with ES5 class-like semantics
What is the purpose of Classes?
= Class declaration introduced in ES2015
→ Just syntactic sugar: On top of existing prototype-based inheritance
→ Does not add anything new to JavaScript
= Classes can add Properties, Methods & Functions
→ Methods created can be ran later: After the Constructor/Object is created
2 Types of Methods:
1. Instance Methods
= Can be called by Instances
2. Static Methods
= Can be called by the Class
How do you define a Class
?
= 2 Ways to define a Class:
1st Way: Class Expressions
#1 Can be Named or Unnamed
= Name given: Is local to Class’ body
→ But can be accessed through the name
property of the Class
#2 Need to be declared
= Before they can be used
→ Due to hoisting restrictions
Body of a Class
= W/in curly braces
→ Where Class members
ie Methods & Constructor are defined
Execution in Strict Mode
= Stricter syntax for optimal performance
→ Normally silent errors thrown
→ Particular keywords reserved for ECMAScript future versions
2nd Way: Class Declarations
= Using Class
keyword
→ Followed by the name of the Class
Code Example
class Event {
constructor(date, time) {
this.date = date;
this.time = time;
}
}
Function Declarations vs Class Declarations
Function Declarations
= Can be called in code before they are defined
Class Declarations
= Need to be defined before they can be constructed
→ Because the Class is hoisted: But its values are not initialized
Class Re-definition
= Re-defining a Class is not possible
→ An Attempt to redefine a Class will result in: SyntaxError
Alerting you that you are trying to declare a variable that has already been declared
...
Part 2 Constructor Methods
Purpose of Constructors & Prototypes
Act as JavaScript’s main method of defining similar & related Objects
Bring similar functionality facilitated through Classes in other languages
= Does not add extra functionality
→ ThusClass
Declaration made available through ES2015: Just syntactic sugar for existing prototype-based inheritance
Rapidly accumulate many different Objects
= By calling a Constructor different times w/ different arguments
→ Reflective of pattern used in built-in constructors
What are Constructor Methods?
= Here are a few definitions:
Mold for creating multiple Objects w/ same Properties & Methods
Special Method for creating & initializing an Object created w/ a
Class
= Can only be 1 special method w/ nameconstructor
in a ClassAny Function that can be used as a Constructor
= No specific distinction within the language
→ Function can be written to be used as a Constructor, to be called as a Normal Function, or it can be used either way
ie JS functions: Are also Object Constructors
Example
function Event(date, time) {
this.date = date;
this.time = time;
}
Types of Constructors
Type #1: Built-in constructors
= Accessible directly in execution environment at runtime
#1 Object()
#2 Array()
#3 String()
#4 Number()
#5 Boolean()
#6 Date()
#7 Function()
#8 Error()
#9 RegExp()
Creation of Values
= There are 2 ways to create values:
Object Literals
Constructors
Object literals vs Constructors
1 Barely any difference
= Can call Methods on Literals
→ Which means JavaScript will turn the Literal into a temporary Object
→ Helping the Method perform the operation
→ Temporary Object is then trashed when it is no longer useful
2 Why are Object Literals better?
a. Easier to read
b. Faster to run
= Can be optimised at parse time
Simple Objects
Example:
Instead of using this...
var obj = new Object(5);
obj.toFixed(2);
You should use this...
var num = 5;
num.toFixed(2);
Type #2: Custom Constructors
= Define Properties & Methods for your own type of Object
Custom Constructor Creation
= Just like creating a Function
→ Capitalize their name: As convention & for identifiability
= A Constructor can also use the super
keyword
→ To call the Constructor of a superclass
Scope-safe Constructors
What are scope-safe constructors?
= Made to return same result
→ No matter if it’s called with or without new
→ Protects against mistake of omitting new
What is the purpose of scope-safe constructors?
= New programmers can accidentally call a Constructor
→ W/o new
keyword
Resulting in bugs
Which constructors are scope-safe?
= Majority of Built-in Constructors
→ ie Object
, Regex
and Array
= They use a unique pattern to call the Constructor
→ So that in the case new
is not used
= Returns a proper Instance of the Object
→ Through calling Constructor again w/ new
Make a Custom Constructor scope-safe
Code Example
function Event(date, time) {
if (!(this instanceof Event)) {
return new Event(date, time);
}
this.date = date;
this.time = time;
}
var event1 = new Event(“September 24th, 2022”, “12:20PM”);
var event2 = Event(“September 24th, 2022”, “12:20PM”);
= Now both these variable definitions (with and without new
), will return an instance of Event
Object.defineProperty()
Method
= Can be used w/in a Constructor
→ To execute the Property setup needed
Here’s a Use Case…
User Input Manipulation
= Before assignment to an Object
→ Manipulate Value given through date
Parameter into a String
Consisting of Date:
followed by the Value
→ & Assign it to the date
property of Object created
Purpose
= Need to manipulate user-given Values
→ Into a suitable/consistent format
Before saving it to an Object
Code Example
function Event(date) {
Object.defineProperty(this, ‘date’, {
get: function() {
return ‘Event: ‘ + date;
},
set: function(newDate) {
date = newDate;
},
configurable: false
});
}
Accessor Properties
= Do not contain any Properties or Methods
→ Create a Getter to call when Property is read
Expected to return a Value
→ Create a Setter to call when Property is written to
Receives Value assigned at Getter as an Argument
= Entire Constructors: Containing Object.defineProperty()
Method
→ Returns an Instance whose date
property can be set or changed in Object.defineProperty()
Method
→ But cannot be deleted
Above Example
After receiving the value of
date
Getter adds
Date:
to beginning of the ValueReturns that
Object.defineProperty
creates these accessor properties
Purpose of Calling Constructor
= So that JavaScript can perform these 4 Tasks:
Create a new Object
Set
constructor
Property of the Object that is the Variable the Constructor is assigned to
= This Property is different from Standard Properties
→ Because it will not be listed
→ And it cannot be overwrittenUnderlying
constructor
property
= Something that cannot be set manually
→ Can only be set up by JavaScript whennew
keyword is usedObject is created to delete
Event.prototype
in the above exampleJavaScript calls Event()
= In the Context of the new Object
→ Result ofnew Event
: Is the new Object
How to Call a Constructor
Create an Instance of it
= Using thenew
keyword
→ And assigning it to a VariableConstructor assigns given Arguments to Parameters indicated in Initial Definition
Then Constructor assigns given Arguments to the relevant Properties
Code Example
function Event() {
}
var myEvent = new Event();
When to use a Constructor
= Creating various similar Objects
→ With same Properties & Methods
Example Use Case
= Creating an Event
If Function exists
= All need to do is use a new
statement
If the new
Keyword is not used
= Alteration of Global Object will occur
→ Instead of the newly created one
W/o new
= Calling a Function w/o a Return Statement
→ this
in the Constructor points to Window
→ Instead of flat8
Thus, 2 Global Variables are created
W/ new
= Context is switched from Global (Window
)
→ To Instance correctly pointing to flat8
Code Example
var flat8 = new Event(‘September 18th, 2022’)
new
not used & in Strict Mode
= Code would throw an Error
→ B/c Strict Mode designed to protect from accidental calls of a Constructor w/o the new
keyword
Check if Object is Instance
= There are 2 ways to see if an Object is an Instance of another:
1st Way: instanceof
Operator
= Right side of the operator must be a function
→ Even if the prototype.constructor
is reassigned, and the constructor
is lost
→ instanceof
operator will still have the accurate information
Code Example
Check a new Event has been created:
flat-8 instanceof Event
= This will return true
2nd Way: constructor
Property
= constructor
property of any object
→ Will point to the constructor function that created it
→ This property is inherited from its prototype
Code Example
myEvent.constructor === Event;
= Returns true
if myEvent
is an instance of Event
Warning
= Using the constructor
property to check the type of an instance
→ It can be overwritten: So it is bad practice
Constructor vs Function Creation
= When writing a Constructor
→ You should use it like a Constructor
= When writing a Function
→ You should use it like a Function
Call as Function w/o new
Code Example
= Call Event
as a Function w/o using new
Event(‘September 18th, 2022’)
= Returns undefined
→ Creates a date
global variable
Overriding existing date
variable
→ Not what we want
Call Function as Function w/o new
= this
is set to the Global Object
→ Which is the Window
object
→ Which is the Browser
Polluting Namespace
= You should prevent pollution of the namespace
→ This is done by not creating Global Variables
= Confirm if this
is an Event
→ And if it is not, use new
to create an Event
→ And return it
Code Example
function Event(date) {
if(!(this instanceof Person))
return new Event(date)
this.date = date
}
Benefit of Constructor Usage
= To create Methods (instead of creating one big object)
→ Inheritance
Inheritance in JavaScript
= Inheritance in JS is different to inheritance in traditional Object-oriented languages
→ Bc it uses Prototype Inheritance
...
Part 3 Prototype
What is the prototype
?
Here are a few definitions:
A Property
= That all Functions automatically getAn Empty Object
= Receives some special treatment
Object created through Constructor
Creates its own
prototype
ObjectOwn
prototype
Object inherits all Properties of its Constructor’sprototype
= Constructor’sprototype
Object is the Parent of its ownprototype
ObjectAny Properties set on own
prototype
Object
= Can override inherited Properties from Constructor’sprototype
New Property
= Setting a New Property to prototype
Object on the Constructor
→ Will be passed down to any Objects created by Constructor
Code Example
Event.prototype.totalLength = 4;
flat8.totalLength; //This will output 4
Properties created on prototype
= Passed down to Instances
→ But can always be overridden on the Instance itself
Code Example
flat8.totalLength = 10;
flat8.totalLength; //Now this will output 10
Prototype Inheritance
= In place of Classes, JS uses the prototype
→ Allows Inheritance to happen
If Object has many of Properties
= And a Special Parent Property called the prototype
of the Object
→ JS Objects inherit all Properties of its Parent
→ These Properties can be overridden by setting the Property on itself
Define Methods on Objects
Most Memory Efficient
Declare methods on the
prototype
Ensuring only 1
displayEvent
is ever createdAnd it is shared between all the Events created
= Done by makingEvent.prototype
their parent
Code Example
function Event(date){
this.date = date
}
Event.prototype.displayEvent = function(){
return ‘This event is on ‘ + this.date
}
Define Instance Methods
= Defining Methods that can be used from all Instances of a Constructor
→ Done on Constructor’s Prototype Property
Code Example
Event.prototype = {
display: function display() {
return “This is the event!”;
}
}
apply
Method
= Belongs to Function.prototype
→ Can be used to call a Function while binding it to an Object
→ Works even if the Function is not connected to the Object, and if the Object is a different type
Can you bind a Function to an Object yourself?
= Yes
→ Can also include Parameters by passing them as an Array as the 2nd parameter of the apply()
Method
Code Example
function displayEvent(other){
return ‘This event is on ‘ + this.date + ‘and on’ + other.date
}
displayEvent.apply(flat8, [flat9])
apply
Use Cases
1. Calling a Function w/ a List of Arguments
= That is a Dynamic List
ie Math.max(4, 1, 8, 9, 2)
→ Use Math.max
on an arbitrary array (instead of a statically set one)
Use Math.max.apply(Math, myarray)
2. Calling it as a Constructor
= Rather than calling it as a function
→ Create a new
Method of Function.prototype
Code Example
Function.prototype.new = function() {
var args = arguments
var constructor = this
function Fake(){
constructor.apply(this, args)
}
Fake.prototype = constructor.prototype
return new Fake
}
= new
method inside Function.prototype
→ Can call constructors with the new
method
→ Will have feel of calling a constructor
Without actually using a constructor
Example Usage
var nextWeek = [new Event(‘September 24th, 2022’), new Event(‘September 29th, 2022’)]
var args = [‘September 20th, 2022’].concat(nextWeek)
var allEvents = Event.new.apply(Event, args)
= Simplify even further, create a Helper Method
Example Helper Method
Function.prototype.applyNew = function(){
return this.new.apply(this, arguments)
}
var allEvents = Event.applyNew(args)
call
Function
= Another Method of Function.prototype
→ Works like apply()
→ Passes parameters differently
Instead of as an array in the 2nd parameter
They are added to the end
Code Example
displayEvent.call(flat8, flat9)
Subclass Creation: 1st Way
= Set prototype
of subclass to an Instance of superclass
→ ‘subclass’ only called once
→ Cannot customize ‘subclass’ on different calls of ‘superclass’
Code Example
var Event = function Event() {};
Event.prototype = new Venue(“Shoreditch”);
Event.prototype.displayVenue = function displayVenue() { return “Venue Submitted” };
var flat8 = new Event();
flat8 instanceof Event; // Outputs true
flat8 instanceof Venue; // Outputs true
Inheritance w/o Power to Override
= In most prototype-based languages
→ There is inheritance without power to override
→ However, JavaScript does not work like this
Here’s a way to do it:
Code Example
function create(parent) {
var F = function() {};
F.prototype = parent;
return new F();
}
Static Methods & Properties
= static
keyword
→ Defines a static method or property for a class
= Called w/o creating an instance of the class
→ Cannot be called through a class instance
Static methods
= Used to create utility functions for an application
Static Properties
= Used for caches, fixed-configuration
→ Or any other data you do not need to be replicated across instances
Unlike prototype
methods and properties which will appear on individual instances
Code Example
class Event {
constructor(date, time) {
this.date = date;
this.time = time;
}
static displayName = “September Events”;
static timeframe(a, b) {
const tdate = a.date - b.date;
const ttime = a.time - b.time;
return Math.hypot(tdate, ttime);
}
}
const flat8 = new Event(123, 2);
const flat9 = new Event(432, 5);
flat8.displayName; //Outputs undefined
flat9.displayName; //Outputs undefined
flat8.timeframe; //Outputs undefined
flat9.timeframe; //Outputs undefined
console.log(Event.displayName); //Outputs “September Events”;
console.log(Event.timeframe); //Outputs …
Bind this
w/ Prototype & Static Methods
Value for
this
= Must be included when calling a static or prototype method
→ Or else thethis
value will beundefined
inside the methodBody is always executed in strict mode
= So this will occur regardless of whether or not the“use strict”
directive is present
Calling Static & Property Methods
= Static & Property Methods cannot be called on their own
→ Must be called as a Property of another Object
Instance Properties
= Must be defined inside Class Methods
Code Example
class Event {
constructor(date, time) {
this.date = date;
this.time = time;
}
}
Field Declarations
= 2 Different Types of Field Declarations:
1. Public
= Do not need to be made w/ Keyword like let
, const
or var
→ Allow Class Definitions to become more self-documenting
→ Fields will always be there
= Can be declared w/ or w/o a Default Value
Code Example
class Event {
date = “”;
time = “”;
constructor (date, time) {
this.date = date;
this.time = time;
}
}
2. Private
= Cannot be referenced from outside of the Class
→ Can only be read or written w/in Class body
Benefit of Private Field Declarations
Use of Field Declarations not visible outside of Class
= Ensures Classes’ users cannot depend onIntervals (which may change version to version)
Can only be declared upfront in a Field Declaration
= Cannot be created later through assigning them the way normal properties can
Code Example
class Event {
#date = “”;
#time;
constructor(date, time) {
this.#date = date;
this.
}
}
Subclass Creation: 2nd Way
= extends
is used in Class Declarations or Class Expressions
→ For sake of creating a Class as a child of another Class
Constructor in Subclass
= Constructor must first call super()
before using this
Traditional Function-based “Classes”
= Can also be extended
Subclass & Superclass both have same method
= Subclass’ method overrides Superclass’
Code Example
class Event {
constructor(date) {
this.date = date;
}
display() {
console.log(`${this.date} is the date of the event.`);
}
}
class smallEvent extends Event {
constructor(date) {
super(date);
}
speak() {
console.log(`${this.date} is the date of a small event.`);
}
}
const houseWarming = new smallEvent(‘September 22nd, 2022’);
houseWarming.display(); // Output: September 22nd, 2022 is the date of a small event.
Inappropriate Use Case
= Classes cannot extend regular (non-constructible) Objects
→ They must extend another Class
Regular Object Inheritance
= For a Class to inherit Methods & Properties from a Regular Object
→ Instead of another Class
Use Object.setPrototypeOf
Code Example
const Event = {
display() {
console.log(`${this.date} is the date of the event.`);
}
};
class smallEvent = {
constructor(date) {
this.date = date;
}
}
Object.setPrototypeOf(smallEvent.prototype, Event);
const houseWarming = new smallEvent(‘September 22nd, 2022’);
houseWarming.display(); //Output: September 22nd, 2022 is the date of the event.
Species Pattern
Allows creation of Objects which are Instances of Superclass that a Subclass extends
= Instead of creating Objects that are Instances of the SubclassConstructor of Objects created by the Subclass
= Overridden & Set to the SuperclassCan create Instances of Superclass that contain more Methods & Properties
= On top of ones defined in original Class Creation
Code Example
class MyArray extends Array {
static get [Symbol.species] () {
return Array; // This overwrites the Object Constructor and sets it to Array instead of MyArray
}
}
const a = new MyArray(1, 2, 3);
//This allows a to access the default Constructors set at Array
const mapped = a.map((x) => x * x);
//Because a.map() uses a method defined in Array rather than MyArray, the variable called mapped will be an instance of Array rather than MyArray
console.log(mapped instanceof MyArray); //Output: false
console.log(mapped instanceof Array); //Output: true
super
vs Prototype-based Inheritance
Advantage of super
= Ability to call Superclass Methods w/in Subclass
Make Superclass calls w/ super
= Call Methods of Superclass w/in a Method being defined in a Subclass
→ Using super
keyword
Code Example
class Event {
constructor(date) {
this.date = date;
}
display() {
console.log(`${date} is the date of the event.`);
}
}
class smallEvent extends Event {
display() {
super.display();
console.log(`${this.date} is a good time for a small event.`);
}
//Since a method with the same name in the subclass overrides the one defined in the superclass, object created with the subclass will have a method called display() which has additional utility to the objects created with the superclass
}
const houseWarming = new smallEvent(‘September 22nd, 2022’);
houseWarming.display();
//September 22, 2022 is the date of the event.
//September 22, 22 is a good time for a small event.
What are Mixins?
Here are a few definitions:
A Class that includes Methods
= That can be used by other Classes
→ W/o need to be Parent Class of those Classes using its MethodsAbstract Subclasses
= Which are Templates for Classes
Rule for Mixins
= Each Subclass can only have 1 Superclass
→ Multiple inheritance from Tooling Classes is not possible
→ Functionality that needs to be inherited must be provided by 1 Superclass
Using Mix-ins
Create a Function w/ a Superclass as Input
= & a Subclass extending that Superclass as OutputOne Class must accept another Class as an Argument
= This Class must also be accepted as an Argument of another Class
Examples of Mix-ins
const calculatorMixin = (Base) => class extends Base {
calc() {}
};
const randomizerMixin = (Base) => class extends Base {
randomize() {}
};
Example Class using Mix-in
class Foo {}
class Bar extends calculatorMixin(randomizerMixin(Foo)) {}
// Base is in the end set as Base { randomize() {} }
Resources for Further Exploration:
Javascript Constructors and Prototypes By Toby Ho
Understanding JavaScript Constructors By Faraz Kelhini
MDN Web Docs: Object.prototype.constructor
VMWare: JavaScript constructors, prototypes, and the new
keyword
Top comments (0)