DEV Community

Cover image for Unpacking JavaScript 02: Object Oriented JS(OOJS) part 1
sk
sk

Posted on

Unpacking JavaScript 02: Object Oriented JS(OOJS) part 1

previous article-emulating prototypes

Object Oriented Programming

1. Object’s: quick overview

object’s are not covered extensively in this section, but an overview of specific concepts that will become useful in upcoming sections, this section assumes you are familiar with the basics of Object’s, therefore will not cover variations of the same concepts, only relevant concepts are reviewed.

1.1 Own property vs prototype

Own properties refer to local properties of an object, locally defined properties (which you can access or set directly with the dot notation or similar methods), while prototype refer to a special object property proto which we covered extensively here. In short own property means local properties and prototype speaks of inheritance.




let obj = {



 name: "John Doe",



 stack: {1: "react", 2: "nextjs", 3: "ionic capacitor"  },



 print(){



 console.log(`${this.name} tech stack ${JSON.stringify(this.stack)}`)



 }



}



obj.__proto__



// putting the above in the browser console and looking up the __proto__ you will see inherited methods and values of obj



// name stack and print are obj own properties



Enter fullscreen mode Exit fullscreen mode

1.2 Setters and Getters

A setter binds a function to an object’s own property, an attempt to set or assign a value to that property calls the function which only takes one parameter




let obj = {
   name: "John Doe",

   stack: { 1: "react", 2: "nextjs", 3: "ionic capacitor" },

    print(){
      console.log(`${this.name} tech stack ${JSON.stringify(this.stack)}`)

     },

    // binding a function to newStack
   set newStack(stack){

      this.stack = stack
   }



}



// assigning a value to obj's own property newStack will call the function passing in the assigned value as the parameter,



obj.newStack = {1: "vue", 2: "react", 3 : "react native"} // runs the setter function



//{1: "vue", 2: "react", 3 : "react native"} will be passed as a parameter, and obj own property stack will be updated as per the function body



Enter fullscreen mode Exit fullscreen mode

A getter, instead of setting a value, on lookup(accessing a value) a function is called and returns some value, a getter takes no parameters.




let obj = {





get getStack(){
  // must always return a value
 return this.stack


}


obj.getStack // runs the getter method and return stack property

//{1: "vue", 2: "react", 3 : "react native"}

Enter fullscreen mode Exit fullscreen mode

You can define getters and setters on object initialization or anytime using the Object.defineProperty/Properties method

1.3 Value by Reference

Objects are values by reference, a variable does not contain the actual object, rather points to the actual object in memory.

let ob = {}

Enter fullscreen mode Exit fullscreen mode

ob is a pointer to the actual object in memory, but not an actual object. If you ever played with C or C++ you may be familiar with pointers, if not here is a short video on pointers which is a useful and powerful CS concept to know




let obj = {name: jane doe}



let obj2 = obj // the actual object is not copied into obj2 from obj, rather obj and obj2 now point to the same object in memory, changing either will reflect on both references

// example: this concept is very useful for state managers(accessing the 
//same object in different places)



obj2.name = John Doe // obj.name now equals John Doe



obj === obj2 // true



Enter fullscreen mode Exit fullscreen mode

Which makes copying objects tricky, which we will cover only one method in passing while building a lite 2dArray module in later articles

2. Inheritance

2.1 Constructor functions

Functions called with the new keyword and returns an object.




function simpleConstructor(){



 this.name = simple Object



}



let newObject = new simpleConstructor() // constructs and returns an object



Enter fullscreen mode Exit fullscreen mode

Steps taken by JavaScript to construct a new object using constructor functions:

  1. When a function call is preceded by the new keyword

    1.1 JavaScript creates a new object and passes it into the function

    1.2 the newly created object becomes the context of the function (meaning the this keyword inside that function now refers to the passed in object)

  2. Every variable preceded by the this keyword e.g this.name becomes own property of the created object

  3. The object is returned as its own independent instance (so we can create as many objects of the same type as we like, changing the value on one will not affect the other)

Constructor functions have a prototype property which is not it’s own prototype object, rather an object that is passed to be a prototype to instances that are created by the function. The function has its own prototype object which it inherits from, this is not passed to instances, rather the prototype property which can be accessed by using the function name.prototype --((read this paragraph slowly may not make sense the first time or even second))




 //for the simpleConstructor function



simpleConstructor.prototype = {



 age: 22



}



Enter fullscreen mode Exit fullscreen mode

Now every object instance created with simpleConstructor will point to the defined prototype with the value 22 for age, Note: the prototype is not created for each and every instance, there is one prototype object, the instances point to it (remember the value by reference idea)

However, we do not need to assign an object to a prototype property, because it is already an empty object, we can just assign values just like any normal object




 simpleConstructor.prototype.age = 22



Enter fullscreen mode Exit fullscreen mode

Changing a value in a prototype object will dynamically update all instances, that inherit from it. However, instances cannot change the value directly, you can change it using the constructor prototype property, for example let’s create two instances of simpleConstructor




let instance1 = new simpleConstructor()



let instance2 = new simpleConstructor()



Enter fullscreen mode Exit fullscreen mode

Accessing

js instance1.age

, JavaScript will first look at instance1 own properties, and see there is no property age, and look further down the prototype chain and find it, the same will happen for instance2, say we change the value of age using the instances




instance1.age = 33



Enter fullscreen mode Exit fullscreen mode

The assumption would be the age property in the prototype would change to 33, and calling any instance getting the age property will yield 33, but that is not the case, because when you set the property age of instance1 like any object in JS, if the property does not exist as own property JS creates a new property age and assigns the value 33, while the prototype property age remains 22, this is basically overriding the property, the same goes for functions etc, if you know classes from languages like Java, this is the same concept, a subclass can override a property or method of a parent by defining it, in its own context or body

So, our instance1 Object has now both the property name and age, on lookup JS will retrieve the own property age, because it exists and there’s no need to look up the prototype chain.




console.log(instance1.age) // 33



console.log(instance2.age) // 22 (does not have own property age)



Enter fullscreen mode Exit fullscreen mode

actual Inheritance

What if we want to create a separate constructor but still need its instances to inherit from simpleConstructor, we can achieve that using Object.create.




function complexConstructor(){

  // this === new object passed on invocation
  // inheriting simpleConstructor own properties to this new object
 simpleConstructor.call(this)



 this.type = complex object



}


// point complex prototype to simpleContructor
complexConstrutor.prototype = Object.create(simpleConstructor.prototype)


// resiting the constructor(parent) property inside proto to point back to original parent
complexConstructor.prototype.constructor = complexConstructor



let complexObj = new complexConstructor()



Enter fullscreen mode Exit fullscreen mode

Let’s break this down, in back of your mind keep the process JavaScript executes on constructors, the whole deal of creating a new object and assigning it to the this keyword of the constructor. Or maybe let’s just do it in steps again:

Step 1 when complexConstructor is executed JS creates a new object and passes it into the function assigning the object to the this keyword (inside the function) such that using the this keyword inside the constructor refers the newly created object.

Step 2 we call simpleConstructor using the call method which takes in an object(context) and simpleConstructor is called in 'this' new context, that is how simpleCon's own properties are inherited by complexCon

Step 3 setting the prototype of complexConstructor to the prototype of simpleConstructor, Object.create creates a copy object from the passed in object

Step 4 resetting the constructor property on prototype to point back to it’s original creator, Object.create affects the pointer to the constructor, the why of doing this depends largely on what you are doing, let’s say you want to create an object that looks and behaves like another object but you do not have access to its constructor directly, you can use the latter objects prototype.constructor to create objects like it. That is the importance of resetting the constructor.

With this process you can create chains of inheritance for example we can create a moreComplexConstructor and make it inherit from the complexConstructor, which consequently inherits from complex’s parent which is simpleConstructor, be careful thou of creating long prototype chains, this can affect performance, JS be looking for values in long chains to get a value. From now on we will be using classes we basically do the same thing we just discussed but more cleaner, classes in JS are syntactic sugar, underneath they are functions, deducing from what we’ve discussed it is clear that an instance can only have one prototype object making multiple inheritance(directly) hard, you have to create long chains, there are workarounds and design patterns using functions and objects, which we will not go into now, but we will explore later as needed.

conclusion

If you want a programming buddyI will be happy to connect on twitter , or you or you know someone who is hiring for a front-end(react or ionic) developer or just a JS developer(modules, scripting etc) I am looking for a job or gig please contact me: mhlungusk@gmail.com, twitter is also fine

Thank you for your time, enjoy your day or night. until next time.

next article- OOJS part 2

Discussion (0)