Nature Photo

Object-Oriented Programming (OOP) in JavaScript – Part 1

Object-oriented programming (OOP) is a significant concept for many general-purpose programming languages such as C++, Java, C#, Python, etc. The OOP is a very important and comprehensive topic by itself in software development. We may examine it in depth in another article. But if we make a simple definition, we can say that OOP is a paradigm in software programming. Thanks to OOP, we can think of our real world as collections of objects which are in relation to each other then we can design and reflect these in our software development. The OOP is a subtitle of imperative programming which is also another paradigm. As I mentioned above, even it is a subtitle of another topic, the OOP is very important and comprehensive subject.

In this article, we will focus only on how to OOP in JavaScript, more specifically objectsclassesencapsulationabstractioninheritance and polymorphism which are principles of the OOP. In JavaScript, there are a few different ways to create objects. Let’s start with the simple way.

When we look at object’s definition, the object consists of related properties and behaviors collection. [3] Like our real world that we said earlier. As it is seen in the below example, it is easy to create object in JavaScript.

let todoItem = {};

// let's see if we really achieved to create an object
console.log(typeof todoItem); // OUTPUT: object

Object’s Properties

We have successfully created our object however it seems useless at this moment. If we want it to make usable and looks appropriate with the object’s definition that we have mentioned above, we should do something more. Let’s continue to build our object and add some properties to it.

let todoItem = {
  id: 20191220101,
  name: "Make reservation for karaoke at 'Cat Ninjas Bar'",
  reminderAt: "20.12.2019 - 12:30",
  priority: "Normal"
};

Now our object started looking as useful and more beautiful. Of course we can leave the object as is now, as a result it is already an object with a few properties. However we won’t. Because there are a lot of wonderful things that we will do with OOP in JavaScript.

Our object has some properties that have already been set with some values. Now, 100 point question is coming: How can we access those properties to use them? JavaScript provides us two different ways to access object’s properties. Let’s see.

// here is the first one
console.log(todoItem.name); // OUTPUT: Make reservation for karaoke at 'Cat Ninjas Bar'

// here is the second one
console.log(todoItem['name']); // OUTPUT: Make reservation for karaoke at 'Cat Ninjas Bar'

There is a caution. If we have created our object’s properties with hyphen like below.

let todoItem = {
  id: 20191220101,
  name: "Make reservation for karaoke at 'Cat Ninjas Bar'",
  "reminder-at": "20.12.2019 - 12:30",
  priority: "Normal"
};

We have to access the properties only with square brackets.

console.log(todoItem['reminder-at']); // OUTPUT: 20.12.2019 - 12:30

So, don’t we able to create properties that are complex data types? Only primitive types? Of course not. Our properties can be any data types, function, another object. If dive into object type, we can see that our properties can be array, map, set, even custom object like our ‘todoItem’.

So far so good. We have created our object and have declared its properties then have accessed them through dot and square brackets notation. However, it is not enough that only reading objects’ properties. In software development, we need to both read and write values to/from properties continuously. Because in our real world, the objects’ features (features mean that properties’ values of objects in the software world) continuously change. Let’s see how we can write new values into our properties.

// firstly print the properties
console.log(todoItem.name); // OUTPUT: Make reservation for karaoke at 'Cat Ninjas Bar'

// then assign a new value and print again
todoItem.name = "Make reservation for karaoke at 'Dog Ninjas Bar' for tomorrow";
console.log(todoItem.name); // OUTPUT: Make reservation for karaoke at 'Dog Ninjas Bar' for tomorrow

Object’s Behaviors

We have said somewhere in the middle of the article, objects consist of related properties and behaviors collections. We have done the property part. Now it is time to start to examine the behaviors of the objects.

Before diving into the object behaviors, we need to look at the special keyword this. The keyword refers to the current object and its context so we can use the keyword to access to the object’s properties and behaviors. Of course we can use it with both dot and square bracket notations.

Let’s see how the behaviors can be defined.

let todoItem = {
  id: 20191220101,
  name: "Make reservation for karaoke at 'Cat Ninjas Bar'",
  reminderAt: "20.12.2019 - 12:30",
  priority: "Normal",

  /**
    * Retrieve the current value of the object's priority value
    * 
    * @returns value of the priority
  */
  getPriority: function() {
      return this.priority;
  }
};

console.log(todoItem.getPriority()); // OUTPUT: Normal

In this example, we have defined a behavior to our object then have called it with dot notation. Also we can do and get the same result with hyphen and square brackets notation, like we have been seen in properties part. But while we access or change the object’s properties, sometimes we may need to execute function(s), statement(s) and/or expression(s) that are related with the property which we try to access or change.

let todoItem = {
  id: 20191220101,
  name: "Make reservation for karaoke at 'Cat Ninjas Bar'",
  reminderAt: "20.12.2019 - 12:30",
  priority: "Normal",

  /**
    * Retrieve the current value of the object's priority value
    * 
    * @returns value of the priority
  */
  getPriority: function() {
      return this.priority;
  },

  /**
    * Change the current value of the object's priority value
    * 
    * @param priority    new value of the priority
  */
  setPriority: function(priority) {
      if(priority == 'High' || priority == 'Normal' || priority == 'Low') {
          this.priority = priority;
      } else {
          console.log('The priority value must be one of the following: High, Normal or Low!');
      }
  }
};

todoItem.setPriority("High");
console.log(todoItem.getPriority()); // OUTPUT: High

Note: It is a good and very nice habit of writing comments in your code. Your comments help other developers who use your code as well as you.

The programming languages should be standardized because an application that is written in a programming language, should have interoperability. So, to achieve this, there should be a standardization and consensus. For example, C++ has ISO standards.

In JavaScript, standardizations are being released by Ecma International under the name of ECMAScript. The latest version is ECMAScript 2019, in other words ES10. So, why did we talk about all these standardization stuff? Because we will see a good feature that have come with ECMAScript 2009 (ES5) and is related with OOP. Getters and setters.

Getters and setters allow us to access our properties in a controlled way. We can relatively easy achieve the same result that in our last example, with getters and setters. Let’s see how.

let todoItem = {
  id: 20191220101,
  name: "Make reservation for karaoke at 'Cat Ninjas Bar'",
  reminderAt: "20.12.2019 - 12:30",
  __priority: "Normal",

  /**
    * Retrieve the current value of the object's priority value
    * 
    * @returns value of the priority
  */
  get priority() {
      console.log("getter");

      return this.__priority;
  },

  /**
    * Change the current value of the object's priority value
    * 
    * @param priority    new value of the priority
  */
  set priority(priority) {
      console.log("setter");

      if(priority == 'High' || priority == 'Normal' || priority == 'Low') {
          this.__priority = priority;
      } else {
          console.log('The priority value must be one of the following: High, Normal or Low!');
      }
  }
};

todoItem.priority = "High" // OUTPUT: setter
console.log(todoItem.priority); // OUTPUT: getter High

As we can see, getters and setters can be used like properties but with some differences. In assignment operation, the setter function automatically called. In accessing operation, the getter function automatically called.

Adding & Removing Properties and Behaviors

Many times, we need to edit our object’s properties and behaviors. There are several ways in JavaScript to adding/removing properties and behaviors to/from the object. Yeah, you are right. Always there are often several different ways in JavaScript to do something. Right point.

Adding Properties and Behaviors

Let’s start with examining the adding new property and behavior to our object.

// adding a property with dot notation
todoItem.createdAt = "20.12.2019 - 06:12";

// adding a property with square bracket notation
todoItem["updatedAt"] = "20.12.2019 - 09:37";

// adding a behaviour with dot notation
  todoItem.getID = function() {
  return this.id;
};

// adding a behaviour with square bracket notation
  todoItem["getName"] = function() {
  return this.name;
}

In this example, it seems clear that we can add new properties or behaviors with both dot and square brackets notations. This way is very easy, right? But there is another way that we will cover next. In the next way, maybe a bit more code may involved. However we will have more control over the properties and behaviors. So, let’s move on.

// defining a property
Object.defineProperty(todoItem, "createdAt", {
  value: "20.12.2019 - 06:12", // the value of the 'createdAt' property
  writable: true, // with assigning true, later we can write new value into this 'createdAt' property
  configurable: true // with assigning true, later we can remove this 'createdAt' property
});

// defining a behaviour
Object.defineProperty(todoItem, "getID", {
  value: function() {
      return this.id;
  }, // the value of the 'getID' property
  configurable: true // with assigning true, later we can remove this 'getID' property
});

// defining getter and setter
Object.defineProperty(todoItem, "todoItemName", {
  // the getter value of the 'todoItemName' property
  get: function() {
      return this.name;
  },
  // the setter value of the 'todoItemName' property
  set: function(name) {
      this.name = name;
  },
  configurable: true // with assigning true, later we can remove this 'todoItemName' property
});

As we said, adding/defining new properties and behaviors with via this feature, we have more control over. This feature provide us to be able to manage our properties and behaviors with some set of rules. For example, via the ‘writable’ rule, we can say to a property, hey man, don’t let anyone to overwrite you.

Removing Properties and Behaviors

Of course we can remove a property or behavior that are not needed anymore from our object. It is also as simple as adding. OK. But how? Here like this.

// removing a property
delete todoItem.createdAt;

// removing a behavior
delete todoItem.getID;

Thank you for reading. See you soon!