Zeroes and Ones

Object-Oriented Programming 101. Objects

Object-Oriented Programming was a paradigm I always eluded. Being a Javascript native (no, I haven't written a single line of Java), and having spent my time more trying to learn Functional JS, concepts like encapsulation, abstraction, inheritance, (don't even get me started with Getters and Setters) were somehow foreign, I knew the basics, but I avoided anything that forced me to use the 'this' keyword like the plague, or like the Corona Virus if we want to be more in tune with the times.

Anyhow, the thing is avoiding OOP is quite a bad idea, because the thing is basically unavoidable and everywhere. Most libraries are written in OOP, hell, even when we do something as simple as array.length() we are flexing the muscles of OOP, using the methods (length) defined in the Array object by virtue of inheritance. For that reason is that I decided to share my learnings in my journey learning about this paradigm.

I'm following the Udemy course 'Object-oriented programming in Javascript' by Mosh Hamedani, so I will follow this structure and then move to other resources.

Objects

Let's start with the first word of OOP, objects. To define an object in JS is super straightforward we do it like this const television = {color: 'yellow', brand: 'GuacamayoTeves'} we use curly braces to define what is called an object literal. The things that describe my object are called properties, simple. Now, what about actions? Functions when inside an object are called methods, and to define them is still simple const television = {color: 'yellow', brand: 'GuacamayoTeves', turnOn: function(){// magic happens}}.

When an object has methods, is said to have behavior. In these cases usually is a good idea to start thinking about a constructor for our objects, because if we want to fix a bug in a method, going through each individual object seems like a bad idea. So how do we create objects in a sustainable manner? Glad you asked (or glad I asked... rhetorically).

Factory Functions and Constructor Functions

A Factory Function looks like this:

// Factory Function
function createTV(color) {
  return {
    color,
    turnOn: function () {
      console.log("random commercial starts...")
    },
  }
}
const myTv = createTV("purple")

This is quite straight forward is a function that returns an object, and we can pass the value of its properties as arguments.

Here is the second option, the Constructor Function:

function TV(color) {
  this.color = color
  this.turnOn = function () {
    console.log("random commercial starts...")
  }
}
const myTv = new TV("red")

The new operator will create a new object and will point "this" to it.

Abstraction

Sometimes we want to define some properties in an object for internal use, we want them to be private as opposed to public, which means, we can use it for the internal behavior of the object but we don’t want someone overwriting it. How do we do that in JS? Simply enough, something like this:

function TV(color) {
  let moment = "now!"
  this.color = color
  this.turnOn = function () {
    console.log("random commercial starts..." + moment)
  }
}
const myTv = new TV("red")

With the above code, I can use the moment to run my method turnOn effectively, but I can't do something like myTv.moment. Important to notice is that the concept of private property is no very 'javascripty', what is actually happening is that we are defining moment in the scope of the constructor function, and by virtue of closures is accessible for our method (our method 'remembers' the environment where it was defined).

Getters and Setters

So, what happens if there is a property I want to read, but not be able to modify? If I use the private technique above, we can't access it, but if it's public then it can be overwritten... Time to introduce getters and setters.

function TV(color) {
  let moment = "soon"
  let brand = "papagayo"
  this.color = "blue"
  this.radius = radius
  this.turnOn = function () {
    console.log("random commercial starts..." + moment)
  }
  // here is the getter
  Object.defineProperty(this, "brand", {
    get: function () {
      return brand
    },
  })
}

I have to be honest, the code looks crazy, but basically in the first argument we define the object where I want to add the property (the this). The second argument defines the name of the property. Third and last is an object with key-value pair, get is a special key, and in the function, we return the property defined in the object. This allows us to use myTv.brand and read the value, but being unable to overwrite it.

Setters? We can change a value, but it can give us the power to validate how is changed, like:

set: function (value) {
 if (typeof value !== 'string') {
   throw new Error('Invalid brand, enter a string');
 }
 brand = value;
}

Above we can see how we can check that the value we enter to change the brand is appropriate.

Well, and that is the first part. Next blog post I will show an example app of a stopwatch I did as an exercise to practice OOP. As a sneak peek, the repo is here. Until next time!

Developed by Cristobal Heiss