Custom Type
All about Custom Types in Javascript
Before class
was introduced to Javascript, programmers had to use Custom Type in order to achieve Object Oriented Programming (OPP).
This concept will allow us to go deeply on the fundamentals of Objects and understand how Objects are created and linked to each other.
Object Type
In JavaScript, functions are objects.
Do not confuse: many of the built-in constructors, like Object, Array, and Function, are actually functions. Thus Object
is type of 'function'
function greet(name) {
return `Hello, ${name}`;
}
typeof greet // 'Object'
typeof Object // 'function'
The Object
(even though it is a function) can have several properties:
Object.assign
Object.create
Object.hasOwn
Object.freeze
Object.seal
...more
And every Object
has prototype
properties:
Object.prototype.__defineGetter__;
Object.prototype.__defineSetter__;
Object.prototype.constructor();
Object.prototype.hasOwnProperty();
Object.prototype.isProtoTypeOf();
...more
How to create an Object
Let's analyze how the creation of a Object
looks under the hood.

- The builder of all Objects (already created by default)
- Creates the
prototype
object - Has a property called
prototype
that points to aObject.prototype
Allows to create a new Object based on the constructor function
let object1 = new Object();
let object2 = new Object();
- The new
object1
is created with a property:__proto__
__proto__
object points to its parentObject.prototype
- All new Objects created share the same
Object.prototype
It's the parent of all Objects. There is only one Object.prototype
(already created).
All new Objects created should point to this. This has all the default properties of an object, which can be overriden by a new Object (allowed by Inheritance!!)
Note that also it has a property called __proto__
set to null
Useful Object's Methods
Assume the Prototype Chain (LinkedList):
Object.create(obj)
Allows to create a child Object from a parent Object
let cheesecake = Object.create(dessert);
Object.getOwnPropertyNames(obj)
Returns all properties of the object passed, as string[]
Object.getOwnPropertyNames(cheesecake)
// [constructor, name, calories, minCalories, displayDessert, ...]
Object.getOwnPropertyNames(dessert)
// [constructor, minCalories, displayDessert, showDessert, ...]
Object.getOwnPropertyNames(Object.prototype)
// [constructor __defineGetter__, __defineSetter__, hasOwnProperty, ...]
Object.getPrototypeOf(obj)
Return the Prototype of the object passed
Object.getPrototypeOf(cheesecake) // returns dessert
Object.getPrototypeOf(dessert) // returns Object.prototype
Object.isPrototypeOf(obj)
dessert.isPrototypeOf(cheesecake) // True
Object.prototype.isPrototypeOf(dessert) // True
cheesecake.isPrototypeOf(Object.prototype) // False
Chain of Properties
Now, let's discuss how chain of properties works in Objects, which is kinda weird but the diagram and example will help.
Notice that all these new Objects created share the same __proto__
. Thus, they all share the same properties from Object.prototype
.
Assume a new object3
points to another object1
, which points to Object.prototype
.
We want to access the property toString
, which is not declared in any of the new objects created.
To search toString
property, traversing is done from bottom (child) to up (parent). The Object.prototype
is the parent of all objects, which is the end of the traverse (end of the chain)

Here is the code.
function findProperty(src, toString) {
let currObj, answer;
/* Traversing the prototype chain */
currObj = src;
while (currObj !== null) {
let currObjProperties = Object.getOwnPropertyNames(currObj);
let found = currObjProperties.find(elem => elem === toString);
if (found) {
answer = found
return answer;
}
currObj = Object.getPrototypeOf(currObj); // go parent object
}
return answer; // if not found, return undefined
}
Function Properties
arguments.length
Returns the number of arguments passed to the function.
function generateResults(x,y) {
console.log(arguments.length)
console.log(arguments[0]);
console.log(arguments[1]);
}
generateResults(); // Output: 0, undefined, undefined
generateResults("Hello"); // Output: 1, "Hello", undefined
generateResults(1,2); // Output: 2, 1, 2
function.length
Returns the number of parameters that the function is expected to take.
function generateResults(x) {
console.log(x);
}
generateResults.length // 1
function moreResults(x,y) {
console.log(x, y);
}
moreResults.length // 2
function.valueOf()
Returns the function in plain text
generageResults.valueOf()
// -> 'function generateResults(x) { console.log(x); }'
this
In Java, this
references the current Object we are operating. this
is fixed (does not change)
In Javascript, this
also references the current Object we are operating, but this
changes where is pointing to depending on the scenerio.
Note:
By default this
is referencing to window
Allows associating functions to an object at runtime
Can set this using apply(), call(), or bind()
window.singer = "Lionel"
function printInfo() {
console.log(this.singer);
// this -> the context where this function will work
}
printInfo() // "Lionel"
// this -> references to window
let obj = new Object();
obj.singer = "Elvis"
obj.singerInfo = printInfo()
obj.singerInfo() // "Elvis"
// this -> references to object
apply()
Allows to specify to the function what this
is refering to
function.apply(obj , args)
Example
let obj = new Object()
obj.terpConstant = 20
window.terpConstant = 10
function product(x,y){ return x * y * this.terpConstant }
product(2,5) // `this` referes to `window` // 2*5*10 = 100
product.apply(this, 3, 3) // `this` refers to `window` // 3*3*10 = 90
product.apply(obj, 3, 3) // `this` refers to obj // 3*3*20 = 180
call()
Similar as .apply()
, useful for Inheritance to populate superclass/parent-class
function.call(object, args)
Example
product.call(this, 3, 3) // `this` refers to `window` // 3*3*10 = 90
product.call(obj, 3, 3) // `this` refers to obj // 3*3*20 = 180
bind()
The bind()
method creates a new function that, when called, has its this
keyword set to the first arugment. The args
allows partially apply arguments, similar to currying functionality.
function.bind(object, args)
Example
const obj = {name: 'Jose'};
function greet(greeting, punctuation) {
console.log(greeting + this.name + punctuation);
}
const boundGreet = greet.bind(obj, "Hello, ");
boundGreet("!"); // -> "Hello, Jose!"
Function Class without class
keyword 🔨
A function
can also work as a Class
. By convention, a function class name starts with Capital Letter.
Warning:
Doing in this way, if we were creating 50 instances of Computer
, then we were creating 50 instances of getMemory
and setMemory
functions.
So this method is inefficient. Can we do better? yes, Sharing Prototypes
// constructor function / Custom Type for Computer
function Computer(model, memory) {
this.model=model;
this.memory=memory;
// DO NOT USE LAMBDA WITH 'THIS'
this.getMemory = function(){ return this.memory }
this.setMemory = function(newMemory){ this.memory=newMemory }
}
Computer("mac", 100); // properties are set to 'window' object
// Create an object from constructor function
let pc = new Computer("PC", 30); // properties are set to 'pc' object
pc.setMemory(100); // property set to 'pc' object
Sharing Prototypes 🤝
We can set these instance functions to the parent Object.prototype, so that all new objects created shares the same common function, without repeately creating one each time a new object is created.
Note:
Only set to .prototypes
properties that share in common between all objects. If want to set a property that is unique between all objects, set it into function constructor
/* function constructo / Custom Type for Car */
function Car(model, year) {
this.model=model;
this.year=year;
}
// Car.prototype.model = "ford" // DO NOT DO THIS
// Car.prototype.year = "2020" // DO NOT DO THIS
Car.prototype.getYear = function(){ return this.year }
Car.prototype.setYear = function(newYear){ this.year=newYear }

How atually defining a Function Class
A long story just to get here. Defining a function class, the right way!, without class
keyword
// Constructor function / Custom Type for Student
function Student(name, credits, courses){
this.name=name;
this.credits=credits;
this.courses=[...courses];
}
// Set Common Properties for all Objects / Static members / Class variables
Student.prototype = {
constructor: Student, // it says: I belong to this constructor
college: "UMCP",
info: function() {
document.writeln(`
${this.name}, ${this.credits}, ${this.courses}, ${this.college} `)
}
};
// Create Unique Students
let student1 = new Student("Kelly", 15, [414,420]);
let student2 = new Student("Jose", 42, [414,420]);
let student3 = new Student("Kevin", 1, [414,420]);
let student4 = new Student("Martin", 60, [414,420]);

Function Inheritance
To understand Inheritance, imagine two custom type
, one is a subset of another. All common properties of a Student
are shared with GradStudents
, such as:
- ID
- Name
- Credits
But GradStudents
may have properties that doesn't have all Students
- Office Room
- Office Hours
- Bachelor's degree
- Thus,
GradStudent
is a subset ofStudent
set.
/*------ Grad Class / Custom Type for Grad ------*/
function GradStudent(name, credits, courses, advisor) {
// Calls super class constructor
Student.call(this, name, credits, courses);
// This says: call Student Class, this = GradStudent, pass arguments
this.advisor = advisor;
}
// Set Static members for all instances GradStudent
GradStudent.prototype = new Student();
GradStudent.prototype.constructor = GradStudent;
GradStudent.prototype.getAdvisor = function() { return this.advisor; }
// Create Unique Grads
let graduateStudent1 = new GradStudent("Kelly", 15, [414, 420], "Dr. Smith");
let graduateStudent2 = new GradStudent("Wiley", 15, [631, 632], "Dr. Will");