cft

A comprehensive look at Object-Oriented Programming(OOP)

A programming paradigm


user

Allan Sendagi

3 years ago | 31 min read

Here is what to expect from this article:
1. The this keyword
2. The new keyword
3. All about prototype
4. ES6 classes
5. Class-based languages like Java and C++
6. Inheritance
7. Object.create
8. Private vs Public
9. The 4 principles of OOP

A programming paradigm allows us to organize code in a way that is easy to reason about.

This is what we hope to get from understanding this programming paradigm:

  1. We will make code more clear and more understandable.
  2. We will make our code easy to extend. Remember, as our app grows, and as our programs grow, as the developers on the team grow, our code is easier to extend using these programming paradigms.
  3. Make code easier to maintain by multiple programmers.
  4. Make our code memory efficient.
  5. It will keep our code DRY. We won’t repeat ourselves. Our code will be clean and efficient.

So it's clear that programming paradigms allow us to make complex code more organized. But before OOP and Functional programming, there was machine code; initially, it was all ones and zeroes that programmers used.

A programming paradigm allows us to organize code in a way that is easy to reason about.

As time passed, we went into a procedural style of programming. With this style, we did what computers wanted us to do — that is we would store data and then manipulate this data using some sort of functions. But there was no structure or organization.

We just had step by step instructions: Computer, put memory here, computer move this memory here, computer change memory here and then give me this. Everything was procedural.

Initially, we started with basic programming languages — really low-level languages. Basic, Assembly language, COBOL, but throughout the 60s and 70s, a big change happened. We started establishing these fundamental paradigms.

How can you write code in a more organized fashion?

Code that isn't procedural. That's when OOP and FP started to take effect. We had languages like Scheme which was one of the inspirations of Javascript. We had languages like Smalltalk which popularised this idea of OOP as a way to organize code.

And finally, in the 80s as more and more best practices started to happen, we started to have more of a consolidation — people agreeing on what some good patterns and best practices are. Things like modules.

Here, OOP really started taking off. We had languages like C++ that came into existence. C++ was the original C language with classes — classes that allowed us to do OOP. We had Objective C and as the name suggests, it was a C based language that was inspired by the idea of objects and OOP. And that's when things really started to take off.

At the same time in the background, we also had functional programming. In the 90s, with the age of the internet, we started having more languages. Java became a hit with its Object-Oriented Paradigm.

In 1995, we had Javascript that came as the language of the web and many other languages that we are familiar with. OOP kept up with the trends and it was really popularised with languages such as Java.

Today, we now see a trend towards Functional programming languages. They are becoming more and more popular, mostly because of the way the paradigm works well with Concurrent and Distributed programming.

This all shows that as the years progressed, programmers as we work more and more with code, we start to develop ideas of what we deem good practices.

This all shows that as the years progressed, programmers as we work more and more with code, we start to develop ideas of what we deem good practices.
So people then were asking themselves what should we do?
And OOP and FP were the two strong paradigms that evolved. And so by learning these two things, we get to stand on the shoulders of giants.

We get to know what are the good practices that all these programmers that came before learned, the mistakes that they made, and in so doing, we write better code.

Object-orient programming Vs Functional programming

In all programs, there are two primary components:
1. The Data — stuff we keep on our memory.
2. The behavior — the things that programs can do.

In order for us to deal with these two things, we initially had languages like Java and Scheme that had different ideas of what we can do(Java and Scheme were the inspiration of Javascript).

We previously learned that there are things like functions and objects in Javascript and that they are really important. We learned all about Prototypal inheritance, about functions, and their useful tools like Closures and the idea that functions were first-class citizens in Javascript.

From these two ideas, we had Functional programming and Object-oriented programming.

OOP says bring together the data and it’s behavior in a single location called an object; putting all this in a box makes it easier to understand how our programs work.

Functional programming says that data and behavior are distinctly different things and should be kept separate for clarity. So perhaps instead of having one giant box to describe everything, we have multiple boxes.

OOP is like building a robot, we have a head component, a hand component, maybe a chest component, legs component, antennae component and we build those together.

Functional programming says just give me data and I will act upon that data through functions and I will return something new from the data that you gave me.

The goal here is not to show you that it's FP Vs OOP but rather that these are actually complementary. It's not one over the other. Instead, it's about using both paradigms in unison to make good programs. The beauty of Javascript is that it's multi-paradigm.

We can use both these techniques to make our code easy to reason about, to make it clearer, to make it understandable, easy to extend, and more efficient. Also, we can use each of these paradigms based on the problems at hand and use the techniques in each to pick a paradigm for a specific problem.

The two pillars finally allow us to learn about these topics.

Closures are a big part of FP and without them, we wouldn't be able to do what I am going to show you with Functional programming. And without Prototypes, we are not going to be able to do the things that we are going to do in OOP.

OOP introduction

Most of the stuff here, we have already seen.
The this keyword, prototypal inheritance, the new keyword, the new ES6 classes, inheritance, Object.create.
We are also going to see private and public fields — the idea of class-based inheritance in languages like Java. And finally, we will cover the four principles of OOP.

OOP has been around since the 70s.

It’s a style of programming that is very common in languages such as C#, Python, Ruby, and Java. In OOP, an object is a box containing information and operations that are supposed to refer to the same concept.

It's like we are modeling real-life objects. And we’ve seen this before with our dragon object. We had some OOP principles here.

We had data about the dragon such as name and the ability to breathe fire. We also had actions that the dragon can take. In OOP, this data can also be called state.
We’ve wrapped this dragon in an object to model a real-life dragon that contains some data about the dragon, and also the actions that the dragon can take.

The attributes or properties allow us to keep track of the state of the object and the methods allow us to manipulate the state of the object so that we model the real world.

The attributes or properties allow us to keep track of the state of the object and the methods allow us to manipulate the state of the object so that we model the real world.

And that's what we want to do with OOP.

We want to look at the world and organize the things we want to do into these small little object boxes that interact with each other. So that we keep everything divided and organized.

When it comes to OOP, there are two main types:
1. There are class-based programming languages.
2. Prototype-based programming languages.

As we know with Javascript, we have Prototypal inheritance. So let's look at the whole journey from procedural code — code that we repeat ourselves into code that goes all the way to OOP.

Let's start with a game that has characters that interact with each other. using Let's create a program that has OOP principles in mind to organize our code.

Creating an elf object

The elf character. source: ZTM
The elf character. source: ZTM

As with any game, we are not going to have just one elf. We are going to have different elves with different names, different weapons, maybe even different methods.
So what should we do if we want to add another elf?

We can copy and paste this code and maybe create elf2.

The second elf character in our game
The second elf character in our game

So what's the benefit of what we have just done that has moved us towards OOP?

We have something called Encapsulation here. We’ve grouped functionality together. We have state — that is data within the object and functions acting on that state.
So that these functions can interact with this state. They can read it or even modify it. We can have a method that maybe changes weapon from let's say bow to the sword.

This is our first step towards OOP.

We’ve encapsulated functionality that can be contained to model real-world elves into these containers. But what's the problem with this?

The clear problem is that when we need more elves — which in this game we are going to need a lot of them, we have to copy the same code over and over even though the elves have the same attack method. We have to repeatedly copy and paste code all the time.

And most likely, we have way more functionality than this for our elves which would mean way more properties, way more methods. We are not keeping our code very DRY. We are just constantly repeating ourselves.

So let's move on to step two towards OOP.

Factory Functions

Factory functions are functions that act like factories — they create objects for us.

Let’s programmatically create elves.

Here we have created a factory function — a function that creates objects for us. And we can even simplify this using ES6 syntax where if property and value are the same, we can just keep it inside of an object.

The beauty with factory functions is that now if I want to create another elf, all I do:

So instead of just copying code, we now have this function that just creates elves for us.

We’ve moved up a step towards OOP.

We avoided repetitive code. But there is still a problem here. Factory functions are great but what's wrong here?
What if we have 1000 elves? It means all 1000 elves require space in our memory to store the same data!

So things like name and weapon are going to be different and we are going to have to store that data in memory for each elf. Also, methods such as attack() that are pretty generic have to be copied unto memory in a different location for each of these elves.
So if we had 1000 elves, that's 1000 attack functions in different places in memory for each elf.

Luckily, Javascript has this thing called Prototype inheritance. We can use that to our advantage to improve this so that we share functionality across different objects.

So let’s move on to step three towards OOP.

We want to solve this issue of having the same functionality on multiple objects. How can we do that?

Before we get to prototypal inheritance, there is one way of going about this manually.

We can take out the attack function, and place it in some sort of a store where we have common functionality. For example, I can do

Now I have a simple object that has the attack method on it and all I need to do now to give the attack ability to Peter and Sam is to add a line of code that says:

peter.attack()
peter.attack()
Sam.attack()
Sam.attack()

Object.create()

This works but it’s still a lot of manual work. Javascript gives us a tool to make this easier on ourselves. We can use Object.create().

With Object.create(), I can clean this up a bit. Instead of manually having to attach the methods onto each elf, we will remove our lines of code and use Object.create() to create that link — that prototype chain between these two parts of the code.

And we can do that fairly simply.

What Object.create does is it creates a link between the elf functions and the newElf that we just created. We are doing Prototypal inheritance here.

What Object.create does is it creates a link between the elf functions and the newElf that we just created. We are doing Prototypal inheritance here.

Object.create creates this prototype chain for us all the way up so that we can use the attack method.

Here is one problem. You won’t see this out in most code bases even though what we are doing with Object.create() is true prototypal inheritance. It’s meant to be used like this.

It's true our code is a little cleaner but this is not very accepted by the Javascript community as a whole.

Our goal is to get closer to Object-oriented programming. But what we are doing here isn't necessarily OOP yet.

So what did programmers use before Object.create()?

Step four towards OOP.

Without Object.create we did something that is even closer to OOP. Instead of using Object.create(), we were using Constructor functions.

Here is the interesting part; I am not returning anything here. I am using this and that's it.

We are constructing an elf.

So how does this work?

Now if I do:

If I run this, I get a type error — cannot read property ‘name’ of undefined.

If I run this, I get a type error — cannot read property ‘name’ of undefined.

And this is because Constructor functions are built like this: In order to use the constructor function, you need to use the new keyword in Javascript.

We see that magically works. But why is that?
That is because the new keyword in Javascript automatically returns the object for us and creates the elf constructor.

Any function that is invoked using the new keyword is called a constructor function.

Any function that is invoked using the new keyword is called a constructor function.

And we’ve seen constructor functions before. Things like Number(), Object() or Function() — capital letters but they were functions.

Those were all constructor functions. You invoke them by using the new keyword. So as a rule, all constructor functions should start with a capital letter to let other programmers know that you need to call this function using the new keyword.

Let's see how we can create an elf using the constructor Function that comes natively in Javascript.

Function constructors simply allow us to use the new keyword and create these objects for us.

But now let's implement the attack function here.

Since we have used the new keyword which automatically returns an Elf object for us and creates our Elf constructor Function, we’ve created a new object. And because this function is called, a new execution context is created.

And since this is a function that we are running — Elf, and a new execution context is created, that means we automatically get the this variable attached to it. Remember that every function that we call gets this and the arguments parameters.

Interestingly here when we use the new keyword, instead of this pointing to the window object, like it usually does, the new keyword changes what this is pointing to when a new execution context is created. Instead, the new keyword will say, I want you to point this to the object that we just created. So that this becomes Peter.

Let's see what happens when we remove the new keyword.

Removing the new keyword

That's because without the new keyword, we are not returning that object and we are also not assigning this to the object that calls us.

So the new keyword does a lot for us behind the scenes in order for this to work.
So it's very important that we use the new keyword which is why we want to use capital letters to indicate to other programmers that we need to use the new keyword otherwise it's not going to work.

The reason this is so powerful is that every function in Javascript gets a prototype property.

The reason this is so powerful is that every function in Javascript gets a prototype property.

A Function is a special type of object. It's a callable object that has code that can be invoked, an optional name, properties that in case we want to give it, we have access to.

But we also get the prototype{} that's created with every new function. This prototype property is absolutely useless with any regular function but when we have constructor functions, this prototype finally becomes useful. Native constructor functions like Function come with things like call, apply, and bind.

Arrays come with reduce, map, forEach because they are built out of the Array constructor function.

In our case, we can add our own to the prototype.

So now we can do:

And we are able to use the Prototype to add functionality to our Elf.

To review,

We are able to use constructor functions instead of something like Object.create() to create this magical function. Our magical function returns a new function and modifies what this means to whatever object calls us. So instead of the global object, this is now going to point to the calling object; Peter and Sam.

Also, since this is a constructor function, we have the Prototype function that we can attach things to.

So that when Peter.attack() gets called, it works. Remember, Peter doesn't have attack() as its own method but it's going to go up the Prototype chain where it's going to find attack.

Now both Peter and Sam are able to use attack() from the same location in memory. Instead of us copying attack() in multiple places in memory, we just have it written once and both these Elves are going to point to the same memory space.

And the beauty is I can just keep adding functionality or methods as the game evolves.

Note: What happens if we change this to an arrow function?

We get undefined.

Remember, arrow functions are lexically scoped. They define this based on where they are written. And this in this case is the global object because who is calling this, there is no Object surrounding it other than the global object.

But by using the regular function, which is dynamically scoped, this is going to change based on who calls it. This one area where you don't want to use arrow functions because you don't want a lexically scoped this.

Let's dig deeper on the constructor functions

console.log(this) gives us Elf as an empty object

Since there are no properties here because we haven't added anything, we just create an empty object.

But if I move console.log(this) down, we see that after we add the name and weapon properties, we have them accessible to us.

demonstrating this

What's interesting is that now if I add a var q=6 to our constructor function, we won't be able to add it to our elf object.

We can only add properties to Elf using this keyword

With a constructor function, the only way we can add properties to the object is by using the this keyword.

We also talked about how constructor functions automatically create that prototype chain for us. So let's test that out.

We see that we have Elf as our prototype because__proto__ points to the prototype of Elf. Remember, Elf.prototype was created for us because of the new keyword.

So that when we finally add onto the prototype an item like attack(), we now have __Proto__ pointing to Elf.prototype which contains the attack() method.

peter__proto__ points to Elf prototype

Now if I do Elf.prototype, we see that it’s the same thing. We have the attack() function inside of this prototype.

If we console.log before we add the prototype:

It’s an empty object

Remember that every function that we create gets this prototype property. But only Constructor functions have use for this prototype Object.

But now what happens If I do Peter.prototype?

peter.prototype gives us undefined

I get undefined. This is because Peter is not a function. Peter is an object. Only functions have access to the prototype.

Note:
One of the gotchas in OOP is something like this:

A function inside of a method is still a function inside a function

Here if I click run, I get undefined.

By why is that?
A Function inside of a method is a function inside of a function. This means that this is not assigned to the object itself but this time to the window Object. There are a few ways to solve this:

bind()

Or we can just have a reference to this

So are we there yet? Or what is the problem with this code?

The problem with this code is prototype is kinda weird. It’s a little hard to understand, isn't it?

This code is not easy to understand unless you really know your prototype inheritance and how Javascript works, which most people don't. This can get very confusing very fast. Not many people like this style of coding.

In older codebases, you might find this style of programing especially if they are doing OOP. The problem is OOP is all about the idea of classes. With this code, there are no classes in here and the capital letter thing which is why Object.create() was added to the language in order to avoid this headache and just use pure prototypal inheritance.
But the idea of this and the new keyword is very much OOP inspired especially when it comes to languages like Java.

The final step to OOP with Javascript.

So how can we improve this? Let's add classes and get as closer as we can to OOP with Javascript.

Everything in Javascript is an object.

Let's try something. We now understand constructor functions. So if I do:

Javascript creates Number 5 for us.

And its a type of Object.

a is a typeof Object because we have used a constructor function

This is not the same as simply saying:

typeof b is a number

And so:

What we are seeing is that there are two different ways of constructing these things in Javascript.

However, if I just do two equal signs I get true because of type coercion.

Interestingly now if I do b.toString I have all these methods I can use on b even though we saw b is a primitive type.

This is because in Javascript when we assign a variable (var b=5), internally Javascript is going to Construct the number that we have added so that we have access to all these methods. And that's how we can use things like toString, toFixed. Even on string values or string primitives, we can have methods like these.

Javascript sees that you want to use Object methods, so it automatically assumes you meant the object instead of primitive so it runs the constructor object internally. This is how things like new Date() works as well.

You are creating objects and it's useful because they have a built-in prototype so that on this date we can run different sorts of methods.

So yes technically in Javascript, everything is an object.

So yes, technically in Javascript, everything is an object.

Everything has a constructor function with the exception of null and undefined. We have constructor functions for everything so that we have methods that we can use on them.

Ultimate OOP in Javascript.

constructor functions

Remember our constructor functions? No one really liked the prototype way of adding methods. So with ES6, Javascript finally introduced the class keyword.

OOP was created with the class keyword idea in mind. A class is a blueprint of what we want to be created.

OOP was created with the class keyword idea in mind. A class is a blueprint of what we want to be created.

Let’s see how this works.

We can simply define our Elf class:

Now as OOP suggests, we want to keep our functionality inside of this box — the class. Our properties, methods, the state, and all the actions together in a contained environment object.

Every time we instantiate we use the new keyword and the class.

This is the true beauty of OOP. We are modeling real-life scenarios. We are creating an Elf’s class which is a blueprint of what we want elves to be like.

Elves have names. They have weapons. They can also act on these properties like attack(). And you can just keep adding methods to the same location that holds the entire Elf object.

Anytime we need to update something or change or add a method, we can just change it here and all the instances of Elf will get that update.

Instance is a common word that you will hear a lot when we use classes.

An instance happens when we call a class and create an object out of the class. For example, Peter is an instance of Elf.

Peter is an instance of Elf

Instanceof, therefore, is the language we can use to say that we are creating an instance of a class.

This with the new keyword is called Instantiation. We are instantiating a class.

If I remove the new keyword I get a very detailed error. Class constructor cannot be invoked without new.

And there you have it. Here, we finally have OOP, or do we?

Not quite.

This is what we call syntactic sugar. Underneath the hood, we are still using prototypal inheritance. We aren't using classes as classes work in other languages. This is the closest that Javascript is going to get to classes.

This is what we call syntactic sugar. Underneath the hood, we are still using prototypal inheritance. We aren’t using classes as classes work in other languages. This is the closest that Javascript is going to get to classes.

Underneath the hood, they are still using the new keyword, with the prototype.

So why didn't we just create classes from the beginning? Wouldn't it make everything easier?

Because classes aren't necessarily the answer to everything. But also as the creator of the language said:

📷📷source: zero to mastery

Brendan Eich was tasked with creating a language that would attract Java developers that were used to classes and OOP concepts.
But at the same time, they wanted to create a competing language. And for marketing purposes, they couldn't make it the exact same.

He had to be creative. He used prototypal inheritance which is different from how classes work in languages like Java and C++.

In other languages, classes are an actual thing. In javascript, classes are still just Objects.

In other languages, classes are an actual thing. In javascript, classes are still just Objects — Everything in Javascript is an object.

Does Javascript have classes?

Yes, they do as syntactic sugar. But the class keyword is just prototypal inheritance.

And some people call this pseudo-classical inheritance because it's not real classical inheritance.

But looking at this, I hope you can see how we go from repetitive code, which was harder and harder to maintain to something a little bit more organized. We’ve created this grouping of functionality that is easier to maintain and extend.

By the way, you might be asking yourself, why don't we just add the attack() method to the constructor?
It’s because every time we use the new keyword and create or instantiate a class, the constructor function gets run simply because each elf has a unique name and perhaps a unique weapon.

But attack() is shared by all instances of the class

If we moved attack to the constructor, that's going to take up memory space.

Instead of creating an attack function from each object which is what we would do if we added to the constructor, and that's something we have tried to avoid. Instead, we just have one. One function in one location that all these instances can access.

Object.create Vs classes

There are people who love classes and people who never want to use them. Some people want to avoid using the new keyword and this because they say it causes too much confusion.

And so this is just personal preference. Highly respected programmers love classes. Other highly respected programmers hate classes. And there is no right or wrong.

But it's important to note that everything we have done with classes can be done with Object.create().

With Object.create() we actually have everything that we need with none of the mess. We are able to create these prototype chains without pretending like we have classes

Some people call Object.create() pure prototypal inheritance as in that's the pure way of doing it instead of pretending like we are someone else.

What you use is up to you. Most of the Javascript community doesn't use Object.create() as much as the class syntax.

In most cases especially the newer codebases that use OOP principles, they will use class but the beauty with Javascript is that it’s multi-paradigm. It allows us to have a lot of options to code the way that we want based on the problem at hand and the team dynamic we have with other programmers.

4 ways to manipulate the this keyword

  1. The first one was this idea of new binding. This binding is used with constructor functions.

The new binding allows us to assign this to the object that we instantiate. So person1 would be the this keyword.

That's one way we can manipulate this keyword.

2. The other way is called implicit binding.

Here this will refer to person. That's implicit binding; it’s the most common one.

3. We also saw explicit binding.
It’s when we dictate exactly what the this keyword should refer to.

Initially, this is going to refer to person just like we saw above. Now if we want this to refer to the window Object we can explicitly tell it what to bind to. And we say bind to the window object.

Explicit binding uses call, bind, and apply to explicitly tell the program hey this is what I want this to be. I want it to be the window.

4. this and arrow functions.

With arrow functions, we learned that unlike all the other times where this is dynamically scoped — it gets determined whenever it gets called, with the arrow functions, we can do lexical scoping. That is wherever we write the function, that's where this binds to.

So that I can do something like this:

Here everything is working because we are using arrow functions. If we didn't use an arrow function and just used a regular function, in that case, this would be the window object which we usually never want.

This all allows us to harness the power of this.

Inheritance

A core of OOP is inheritance — passing knowledge down.

Remember at the start we decided to create this fairy tale game that had all these characters. And we started with Elves. But as you can see our goal is to have many things, not just Elves.

We want to have a dragon, knight, king, queen, and maybe some magicians.
So using this OOP principle of inheritance, how can we accomplish this with the work that we’ve already done?

Let's say that I wanted to have a new player, and this player is an Olga called Shrek. How would I go about creating this Olga?
Of course, the worst thing I could do is copy and paste this code to create an Olga class.

Copying and pasting code something that we want to avoid.

One option we have is to copy the elf and extend it. In order to copy what we already have, we can use the spread operator.

Here I have copied Peter into the Ogre variable.

But now if I do Orge__proto__ I get the base object.

And Peter?

I get the Elf.

So I have cloned the object but Ogre doesn't have Elf as the base class.

These objects are not referring the same place in memory. They are completely different things. But I have also lost the prototypal inheritance chain.

I can’t even do Orge.attack().

I don't have attack() — so that's a problem.

How can we extend this?
This is where inheritance comes in. It used to be really difficult to do with Javascript before we had this class syntax. It involved a lot of ugly prototype code.

We have changed the naming a little bit with our example. Our superclass is now Character.
From this superclass, Elf extends — which is a keyword the Character class.

This something called subclassing in OOP.

That is we have a base class or a superclass and a subclass. We want to inherit from the Character class all its properties and methods and create something new out of it extended with Elf.

Let's make this more interesting. Let's say that the Elves have an extra property — a type property to let us know what type of Elf they are.

How would we go about doing that?
Let’s add the type property. If I add a constructor and I do this.type = type, does this work?

We have to instantiate the Elf class and give it the name and weapon; also we want to have the type. So maybe we will have a third parameter.

class Elf extends Character means set the prototype __proto__ to point to Character. Elf now has a prototype chain up to Character.

Must call super…..

What this is saying is that in order for us to have our constructor and be able to use this, and know what this is referring to, we need to call super which here is Elf and not the Character, we have the special keyword called super.

And by doing super inside of the constructor, it says call the superclass of Elf which is Character. So it goes up and calls the Character so that we can create this.name and this.weapon.

Inside super, we have to pass it name and weapon.

Now, this is standard especially with class-based languages where super is referring to the superclass.

Because in order to use this keyword inside of the constructor, when we extend something, we have to call super first.
So that if I move the console.log() under and I run, I have Elf that has name and weapon attached to it.

This is because when super runs the constructor, we now have an instance of character with these properties and we can use this.type to add type to it.

So that by the very end of our construction process, we have all our properties set.

Remember this keyword simply says who I am I? Who is calling me? In this case, we use the new Keyword so that this is going to be set to Elf.

But we started this video with us wanting to create an Ogre. So let's create another class.

And if I do makeForte() here and run this, I am able to use makeForte() method or function on Shrek.

But If I go and make Dolby make forte, I will get an error.

We are able to keep our code nice and organized and extend our base character to create all these different characters in our game. We can reuse the code that we’ve written before, but also extend these classes to have their own unique things — properties like type or even methods like makeForte.

Creating makeForte() meant that we created our own method just for the Ogre class. But we did underneath the hood is we extended the prototype.

It’s the same as saying Ogre.prototype.makeForte(). Underneath the hood Javascript created this for us because we used the class keyword.

It looks a lot nicer than having to use prototype but also as we have seen before, it can get a little confusing. Beyond the fact that it looks a lot cleaner, things just make sense and we are using some OOP principles like classes, extend, and using subclasses.

We are also using the new keyword to create instances. Underneath the hood, we are using prototypal inheritance of Javascript to make these prototypal chains between our objects.

To test that everything is connected properly, let's do a few tests.

Ogre is a constructor function so we do Ogre.prototype which is the object that contains all properties and methods available.

character.prototype. isProtorypeOf(Ogre.prototype)

All this prototype stuff is confusing. There is a better way to check these connections using is instanceof.

We get true because Dolby extends all the way from Character.

Instance is when we use the new keyword from a class. We create an instance of a class. Instance is essentially creating a version of the class.

Instance is when we use the new keyword from a class. We create an instance of a class. Instance is essentially creating a version of the class.

Inheritance — which is what we do with the keyword extends, is inheriting something from a higher class. Inheritance in Javascript doesn't actually copy our functionality. Instead, it simply links up the prototype chain so you are not creating copies and making things inefficient.

Instead, whenever it doesn't find something lets say in the Ogre class, it's going to look up the Ogre superclass which is character.

So it's creating this efficient linking in Javascript using prototypal inheritance. And, unlike other class-based languages, Javascript is just object s— its objects inheriting from objects. There are no technical classes. Languages like Java on the other hand have actual classes. They are a thing.

And classes inherit from classes. The interesting thing is languages like Java and C++ actually copy objects when we do something like extend. Instead of what we do with Javascript which is we link and the objects are referenced. There is actually a bit of efficiency there in terms of memory.

Public vs Private

In many OOP languages that have classes, the idea of private and public fields is really important. In Javascript, we don't have that.

For anything that shouldn't be accessed, from a class or even an object, we would add an underscore to let other people know that hey this is private. You shouldn’t call it. But underscore doesn't really do anything.

I can still use this method and maybe even by mistake reassign it to just false.

So that now I have just overwritten everything.

Other languages like Java have things like private — a keyword that makes things private and may only be used inside of the class.

But there is an Ecma script proposal coming up to solve this issue.

The Ecma script proposal is in stage three and its for class field declarations and perhaps a few more changes.

For now, the closest to doing or having private state or private data, that can only be accessed inside of the class is something we are working towards.

OOP in react.js

By now you can spot OOP in the wild.

For example, if you ever used react.js, you can see how they use OOP principles.

source: https://reactjs.org/

We can now look at the code and understand it better. We have a timer class that we create that extends React.component. React.component is something that comes from the react team. They’ve built this class that has all these features for us so that we can use things like render() that comes automatically for us.

We are using someone else’s code and we are extending the base component there to add our own features. We have constructors that receive props. We have state — the state of our toggle class, and then we create our own methods on this class such as tick().

The pillars of OOP

We started with an idea of building a game. Using this idea we started learning about OOP and how we can use this programming paradigm to better our code and make it more organized. Inadvertently, we just learned the four pillars of OOP.

  1. Encapsulation: Remember that before OOP we had procedural programming. Unlike procedural programming where we have functions modifying data with no real structure, OOP puts Objects in a container and organizes things into units that model real-world applications.

This is Encapsulation. We wrap code into boxes that are related to each other so that these boxes can interact with each other using methods and properties that we make available. This makes code easier to maintain and more reusable. Here we have all these nice class packages that we can just use whenever we want.

2. Abstraction: This just means hiding the complexity from the user. That is creating simpler interfaces such as taking care of the class and that's left to do is to instantiate the class. Such as an instance of an Elf with all the properties and methods already there for you.

And the idea of abstraction says here are the properties and methods that you can use don't worry about anything else. I will do all the calculations behind the scenes. This reduces complexity because we can just see the methods and understand what a class can do. Abstraction also helps when we have private methods and private variables — something that Javascript is working towards.

3. Inheritance: By inheriting from other objects we avoid rewriting the same code and we also save memory space by having shared methods.

Inheritance is a very powerful concept and its definitely my favorite part of OOP.

4. Polymorphism. The word itself means many forms. polymorphism is heavily debated. There are many interpretations of what it means. But the idea is to call the same methods on different objects and each object responds in a different way.

Here let’s say that the Elf and Ogre class have a different way of attacking. For example, the Elf attacks with a cry, and the Ogre just returns arrrghhhh.

Now running Dolby.attack(wee) and Shrek.attack() gives us weeeeeee and arrrghhhh.

This is a very basic way of what polymorphism is but the idea of the ability to appear in many forms is there. We are simply overriding the attack() method where the same method acts differently for each type of class. Or we can do method overloading which is adding extra features or extra parameters to add on to what that method can do.

The idea with polymorphism in OOP is that it has the ability to process objects differently depending on their data type or class. Now because Javascript is a dynamically typed language, it limits the amount of polymorphism that we can have but the idea is still the same.

The ability to redefine methods for derived classes and allowing us to reuse some of the functionality but also customize methods to their own objects and classes. Polymorphism is useful because we don't have to necessarily copy and paste code over and over. We can use some of the functionality from the superclass to adapt to our own specific needs.

And these are the four pillars of OOP.

And we have been using them all along. With the help of these pillars, we accomplished the goal that we set out to do at the beginning of this section.

We created code that is clear and understandable.

Code that is easy to extend.

Easy to maintain because we don't have to worry about those prototype chains. We just used simple classes. Everything inherits from a superclass. And if we have to make a modification on a class we can just modify it in one location.

We also learned how memory efficient it is especially in Javascript where objects use references instead of cloning and copying each other.

And then finally, we are able to make our code DRY. We don't keep repeating ourselves over and over for each object. Instead, we have one place where we could create functionality.

So now we have a way to think about code in a critical and intelligent way; to structure your code. Instead of writing code one by one, line by line, you now have a baseline to start thinking about code and how you should organize it. How should different things speak to one another in order to create these programs that have these ideas in mind?

Exercise on polymorphism.

And there you have it with OOP.

So what did we learn?
1. The this keyword
2. The new keyword
3. All about prototype
4. ES6 classes
5. Class-based languages like Javas and C++
6. Inheritance
7. Object.create
8. Private vs Public
9. 4 principles of OOP

Upvote


user
Created by

Allan Sendagi

Technology will save homo sapiens from extinction


people
Post

Upvote

Downvote

Comment

Bookmark

Share


Related Articles