DEV Community

Cover image for Object Oriented JavaScript
Kinanee Samson
Kinanee Samson

Posted on • Updated on

Object Oriented JavaScript

Good day guys, in this article we are going to be discussing about Objects in JavaScript, how OOP (object oriented programming) is implemented in JavaScript. The things we will be discussing about includes:

  • Creating Objects
  • Classes
  • encapsulation
  • Inheritance
  • Polymorphism
  • methods of the Object data type

What is OOP?

To keep it simple Object Oriented Programming is a way of programming that involves modeling our code around real life objects. Say we are working on a code about heroes, we can define a template (class) that specifies what a hero is and then we can create the actual heroes from it, and each hero would make a reference to hero object that is based on the template we provided.

We can write another article about OOP but that is not in the scope of this article. We just want to discuss about how it is implemented in JavaScript, if you are curious about OOP and you want to read more about it i advice that you check this article.

Creating Objects In JavaScript

An object in JavaScript is just a collection of key-value pairs, separated by comma and housed within curly braces {}. That object can be assigned to a variable at the point of creation. The keys are used to store and identify a value inside an object, using the key or named identifier we set for that value. Each value is assigned to a named identifier by a colon for example name:sam however they must be enclosed inside curly braces {key: value, key: value}. The keys can store any type as a value, it can be an array or a string or a function or even another object, but you get the point? The properties on the object can then be accessed using square bracket or dot notation.

There are three ways that we can create an object in JavaScript and it includes;

  • Using object literals
  • Defining a constructor function.
  • Using the built in Object constructor

Object Literals

We can easily create an object literal in JavaScript, the literal maybe an empty object or we can populate it with key-value pairs, we can access the properties on the object using dot notation or square bracket notation.

let's see how;


let hero = {} //empty object literal;
let myHero = {
    name: 'superman',
    alias: 'clark kent'
} //object literal with key-value pairs

console.log(hero) // {}
console.log(myHero) // {name : 'superman', alias: 'clark kent'}
console.log(myHero.name) //superman dot notation
console.log(myHero['alias']) // clark kent square bracket notation

Enter fullscreen mode Exit fullscreen mode

You would agree with me that this is a simple way of creating a plain object,

Built in Object Constructor

There is a built in constructor function that we can use to create an object

let hero = new Object() //Built in Object constructor
Enter fullscreen mode Exit fullscreen mode

We can tack on properties to the object after we have created it.

hero.name = 'superman'
hero.save = function (person) {
    return `${this.name} saved ${person}`
}
Enter fullscreen mode Exit fullscreen mode

We can then use those properties later


console.log(hero.name) // superman
console.log(hero.save('louis lane')) //superman saved louis lane

Enter fullscreen mode Exit fullscreen mode

We can create a new object based on a previous object by passing the previous object into the constructor function;


let hero2 = new Object(hero)
console.log(hero2.name) // superman

Enter fullscreen mode Exit fullscreen mode

If we pass in a previous object to the function, it will copy the properties of the previous object to the new object, we can also use Object.create() method and it works similarly to the constructor method;


let hero3 = Object.create(hero)
console.log(hero3.name) //superman

Enter fullscreen mode Exit fullscreen mode

Defining a constructor function

We can define a custom constructor function that will act as a class to subsequent objects created from it. We can verify thus using the __proto__ function which is attached to all objects to show you the object they inherit from. A custom constructor function is just a function that can be used to create a custom object. It's __proto__ property will point to that object, when we use the custom constructor function with the new keyword


function Hero (name) {
    this.name = name;
    this.save = function (person) {
        return `${this.name} saved ${person}`
    }
}

let superman = new Hero('superman')
console.log(superman.save('louis lane'))
// superman saved louis lane
console.log(superman.__proto__)
// Hero {}

Enter fullscreen mode Exit fullscreen mode

Classes

ES6 specification of JavaScript provided a cleaner way of handling custom constructor functions for JavaScript Objects by introducing the class keyword. It handled object creation in a traditional manner that can be compared to what is done in some object oriented languages.

class Hero {}
Enter fullscreen mode Exit fullscreen mode

And we have created a simple class, this is just an abstraction of the previous method of handling class creation using custom constructor function. We can add properties and methods inside the object, all objects created using this way can define a constructor function inside them that must be named constructor.

class Hero {
    name;
    constructor(name){
        this.name = name
    }
    save (person) {
        return `${this.name} saved ${person}`
    }
}
const superman = new Hero('superman')
console.log(superman.save('louis lane'))
// superman saved louis lane
console.log(superman.__proto__)
Enter fullscreen mode Exit fullscreen mode

Observe the way methods are added to the objects. we just give it a name and then parenthesis and curly braces, if we tried to get the __proto__ property on the object it would point to Hero {}.

Getter and Setters

When we use the class keyword to define a custom constructor function we can define a getter and setter function that can be used to get and set a property of the object.

class Hero {
    constructor(name){
        this._name = name
    }
    save (person) {
        return `${this._name} saved ${person}`
    }
    get (){
        return this._name
    }
    set (newName){
        this._name = newName
    }
}
const superman = new Hero('superman')
console.log(superman.save('louis lane'))
// superman saved louis lane
console.log(superman._name)
Enter fullscreen mode Exit fullscreen mode

And it get and set the appropriate variable. But the key must begin with an underscore character

Encapsulation

It is required that all properties of an object should be housed within the object itself, this is the basis of encapsulation. Encapsulation is achieved in JavaScript when we define a class or a custom constructor function. All the properties and methods that the object will possess is stored inside the class, when the class is instantiated (creating an instance of a class, which is the actual object we are creating) the properties specified on the class will be housed within the object and only that object can have access to that property. This is why we use the this keyword when we are defining the class or the custom constructor function, it binds the current instance of an object to it, so when we say this.name = new name and we later tried to set the value, JavaScript will take that particular object's name, or if you prefer that particular instance of that class and replace this wherever the this keyword is used inside it.

Inheritance

Inheritance in JavaScript is prototypical, by that i mean that we say that one class inherits from another class by saying that the sub class is a prototype of the base class, inheritance can be achieved with custom constructor functions and classes. Let's see how we can achieve this with custom constructor the prototype property.

function Hero(name, alias){
    this.name = name;
    this.alias = alias
} //base class

//we can add properties to the prototype property of our Hero class
Hero.prototype.savePerson = function (person) {
    console.log(`${this.name} saved ${person}`)
}

// ceating a class that will inherit from the Hero class
function DCHero(name, alias){
    //we don't need to manually set the properties like in the Hero class
    Hero.call(this, name, alias) // we use the Hero constructor
}

//finally we set the prototype property of DCHero to be same with Hero class
DCHero.prototype = Object.create(Hero.prototype)
// creating an instance of a hero
const superman = new DCHero('superman', 'clark kent')

superman.save('louis lane')
console.log(DCHero.prototype)
Enter fullscreen mode Exit fullscreen mode

When we set the prototype of the class to be equal to another class it inherits the properties defined on the prototype property of the base class we are inheriting from. If we want a method or property specified on the class to be defined on inherited classes we can add the property or method to the prototype property of the base object. Observe how we use Hero.call(this, name, alias), what we are simply doing here is calling the Hero constructor and using it to create an instance of a DCHero since they are accepting the same arguments. What if we wanted to modify the DCHero class slightly so it accepts a third parameter when we are instantiating it? Maybe a movie the hero featured in?

function Hero(name, alias){
    this.name = name;
    this.alias = alias
} //base class

//we can add properties to the prototype property of our Hero class
Hero.prototype.savePerson = function (person) {
    console.log(`${this.name} saved ${person}`)
}

// we added a third argument to the constructor function
function DCHero(name, alias, movie){
    Hero.call(this, name, alias) // we use the Hero constructor
    this.movie = movie
}

// inheritance is still the same
DCHero.prototype = Object.create(Hero.prototype)

const superman = new DCHero('superaman', 'clark kent', 'man of steel');

superman.save('louis lane')

Enter fullscreen mode Exit fullscreen mode

Class Based Inheritance

We can inherit from another class when using ES6 classes by using the extends keyword. The sub class extends the base class. The syntax is shorter and less verbose than the custom constructor method. Let's see how we can achieve this.

class Hero { //base class
    constructor(name, alias){
        this.name = name;
        this.alias = alias
    }
    save (person) {
        console.log(`${this.name} saved ${person}`)
    }
}

class DCHero extends Hero{ // sub class with extra argument in constructor function,
    //it extends Hero, hence it is inheriting from it.
    constructor(name, alias, movie){
        super(name, alias)
        this.movie = movie
    }
}

const batman = new DCHero('batman', 'bruce wayne', 'superman vs batman');
batman.save('robinhood')
console.log(DCHero.prototype) // Hero
Enter fullscreen mode Exit fullscreen mode

Polymorphism

Polymorphism is a concept in OOP that specifies that sub classes can have different implementation of the same method. A method or property can be defined on the Base class and in the sub class we specify a different logic inside that function, or we set that property to be equal to something else, let's see a typical example.

class Hero { // base Hero class other classes will inherit from
    constructor(name, alias){
        this.name = name;
        this.alias = alias
    }
    universe;
    save (person){
        console.log(`${this.name} saved ${person}`)
    }
}

// sub Marvel Hero class to inherit from Hero
class MarvelHero extends Hero {
    constructor(name, alias){
        super(name, alias)
    }
    universe= 'marvel universe'
    save (person){
        console.log(`${person} saved by ${this.name}`)
    }
}

// sub DC Hero class to also inherit from Hero
class DCHero extends Hero {
    constructor(name, alias){
        super(name, alias)
    }
    universe= 'dc universe'
    save() {
        console.log(`${this.name} has saved the day`)
    }
}

const sipderman = new MarvelHero('spiderman', 'peter parker')
const superman = new DCHero('superman', 'clark kent')

console.log(spiderman.universe) // marvel universe
console.log(superman.universe) // dc universe

sipderman.save('mary jane') // louis lane was saved by spiderman
superman.save() // superman has saved the day
Enter fullscreen mode Exit fullscreen mode

The DCHero and the Marvel both inherit and implements the save function, however each sub class has it's own definition or implementation of the method, and that's how polymorphism can simply be achieved in JavaScript.

Methods of the Object data type

There are some built in functions that we can use on objects to make working with them simpler, let's look at a few of them.

Object.keys

This method simply return an array of the keys of an object, take note, only the keys and not their values, their exists a different method for that.

const hero = {name: 'thor', universse: 'marverl'}
const heroKeys = Object.keys(hero)
console.log(heroKeys) // [name, universe]
Enter fullscreen mode Exit fullscreen mode

Object.values

This method returns an array of the values of the keys of an object, it is similar to Object.keys, however it returns the values of the different keys on the object as an array

const hero = {name: 'cyborg', universe: 'dc'}
const heroKeys = Object.values(hero);
console.log(heroKeys)
Enter fullscreen mode Exit fullscreen mode

Object.freeze

This method freezes up an object and prevents any modification of the keys specified on the object.

const hero = {name: 'ironman', alias: 'tony stark'}
Object.freeze(hero)
hero.name = 'something else' //not possible
Enter fullscreen mode Exit fullscreen mode

Object.isFrozen

This is used to check if an object if froozen or not, if the object is frozen, it returns true, if it is not froozen,it returns false.

const hero = {name: 'ironman', alias: 'tony stark'}
Object.freeze(hero)
Object.isFrozen(hero)? console.log(true) : console.log(false) //true
Enter fullscreen mode Exit fullscreen mode

Object.assign

This is simply a way of assigning the key-value pairs on one object to another object

const powers = {power: ['speed', 'strength', 'stamina']}
const hero = {name: 'superman'}
Object.assign(hero, powers)
console.log(hero) // { name: 'superman', power: ['speed', 'strength', 'stamina']}
Enter fullscreen mode Exit fullscreen mode

Object.entries

This method creates an array containing the different arrays that maps to each key-value pair on the object. It is an arrays of arrays, each key-value pair is mapped to an array, the first value is the key while the next is it's value.

const DCHero = {
  name: 'superman',
  world: 'krypto',
  weakness: ['magic', 'cryptonite'],
  powers: ['speed', 'strength', 'heat vision']
}

const arr = Object.entries(DCHero)
console.log(arr) /* [
  [ 'name', 'superman' ],
  [ 'world', 'krypto' ],
  [ 'weakness', [ 'magic', 'cryptonite' ] ],
  [ 'powers', [ 'speed', 'strength', 'heat vision' ] ]
] */
Enter fullscreen mode Exit fullscreen mode

This will be all for now, do have a nice day and until next post.

Top comments (6)

Collapse
 
begroff profile image
Brett

Great post. In the defining constructor function section, instead of new Person, I believe it's supposed to be new Hero.

let superman = new Person('superman')
Enter fullscreen mode Exit fullscreen mode
Collapse
 
myleftshoe profile image
myleftshoe

Thanks for the post! Did you forget to add extends Hero in the class definitions for DCHero and MarvelHero?

Collapse
 
kalashin1 profile image
Kinanee Samson

Thanks for the heads up, fixed it

Collapse
 
tuliocalil profile image
Tulio Calil

awesome post, what you think to use Summaryze to create ref links to your summary?
summaryze-forem.vercel.app/

Collapse
 
lyrod profile image
Lyrod

I see "universe: 'marvel...'", but you mean "universe = 'marvel...'" ?

Collapse
 
kalashin1 profile image
Kinanee Samson

Typo! 😑😑.. Fixed it.