DEV Community 👩‍💻👨‍💻

Cover image for Object oriented JavaScript part 3
Tristan Elliott
Tristan Elliott

Posted on • Updated on

Object oriented JavaScript part 3

Introduction

This is part 3 of my notes on The principles of object oriented programming in JavaScript by Nicholas C. Zakas. This post will be on JavaScript objects and how they relate to object oriented programming. If you have questions or concerns about this post feel free to reach out to me on twitter.

Objects

  • A very large part of JavaScript programming is simply managing objects, because of this in order to understand JavaScript as a whole you must have a solid understanding of objects.

Defining Properties

  • There are two basic ways to create your own objects, using object literals or using object constructors. Below is an example of the two methods, it should be noted that they are equivalent to each other.

        // Object literal syntax
        const person1 = {
            name:"Bob"
        }
    
        // Object constructor syntax
        const person2 = new Object()
        person2.name = "Bob"
    
  • When a new property is added to an object(like name and person1) JavaScript calls an internal method called [[Put]] on the object. This internal method creates a spot on the object to store the property. When [[Put]] is called it creates what is an "own property", this simply means that the instance of that object contains the property. For example person1 creates an "own property" called name with the value of Bob.

  • When a new value is assigned to an existing property, an internal method called [[Set]] is called. [[Set]] replaces the current value of that property with a new value.

       const person ={}
       person.name ="Bob" // [[Put]] is called
       person.name ="Tim" // [[Set]] is called
    
  • Above demonstrates when and what internal methods are called.

Detecting Properties

  • There will come a time when you want to check if an object contains a property. A normal reaction is to use an if statement and dot syntax.

      if(person.name){
         console.log("What is do")
      }
    
  • This might look like it will work and sometimes it will but do to JavaScript's type coercion this can cause unwanted bugs. The conditional will not always be determined by the existence of name on the person object. It will be determined by the truthy and falsy value that name holds.

  • A much more reliable way to is to use the "in" operator for property detection.

     console.log("name" in person)
    
  • The code above will return a Boolean value depending if name exists on the person object or not. It should also be noted that the "in" property also checks the object prototype. This means that it will return true if the property exists on the prototype or the object instance. If you just want to check the current object then you should use hasOwnProperty().

     person.hasOwnProperty("name")
    
  • The code block above demonstrates that you simply use dot syntax to use hasOwnProperty().If you are confused with how the person object has access to hasOwnProperty(), then I would recommend that you brush up on prototypes(my next post is on prototype). The person object has access to that method because it uses JavaScript's built in inheritance of prototypal inheritance.

Removing Properties

  • To completely remove a property from an object you need to call the delete operator, setting a property to undefined will not do the trick. The delete operator calls the internal JavaScript method [[Delete]] and when the delete operator is successful it will return true.

     const person ={
           name:"Bob"
     }
     console.log("name" in person) // true
     console.log(delete person.name) //true
     console.log("name" in person) // false
    
  • With the last line of code from above, you can see that the delete operation was a success and that "name" no longer exists on the person object.

Enumeration

  • By default all properties that we add to an object are enumerable and being enumerable means that the property can be looped over. An enumerable property has its [[Enumerable]] attribute set to true. However, not all properties all enumerable and most of the native methods on objects have their [[Enumerable]] attribute set to false.

Types of Properties

(DEEP END WARNING)

Below is wading into the deep end of JavaScript and if you are just learning the basics then you consider this the end of the post.

  • When we are dealing with objects, there are two types of properties, data properties and and accessor properties. This upcoming section relies quite heavily on your ability to distinguish the difference between data properties and accessor properties. So please pay extra attention when I am explaining the difference, take it slow and form your own solid definition.

Data Properties

  • All the properties that you have seen up to this point have been data properties. Data properties are just your generic properties that hold a name and a value. The default of the [[Put]] method is to create a data property. So long story short, data properties are just normal properties.

         const person = {
             name:"Bob" // <-- data property
          }
    

Accessor properties

  • These types of properties don't actually contain a value at all. Instead they define functions to call when a property is read(getter) and a function to call when a property is written(setter). There is even a special syntax used to define an accessor property using an object literal. The code block below will show it.

        const person ={
           name:"Bob",
    
           get name(){
             console.log('reading ' + this.name)
             return this.name
           },
           set name(value){
             console.log('we are writing a new name value')
             this.name = value
           }
         }
    
  • As you can see from above the special syntax is to place get and set before the name of the function. It should be noted that the name of the function and the name of the property must be the same. That is why both get and set are called name. Also, the getter(get name()) is expected to return something while the setter(set name()) is not. Usually these getter and setter functions are used to add additional functionality to the actions of reading and writing properties. You will not see them often but they are still useful to know.

  • Just to summarize, data properties are normal properties and any function with a get or set before are accessor properties.

Property Attributes

-Prior to ECMAScript 5 there was no way to to access the internal attributes of a property at all. Now thanks to ECMAScript 5 it is possible to create properties that behave the same way as built in properties.

  • While accessor properties and data properties are very different they share some properties attributes. The first being [[Enumerable]] which we have already seen. The second being [[Configurable]], which determines if the property can be changed or not. By default all the properties that we make have both [[Enumerable]] and [[Configurable]].If we want to change property attributes we can use Object.defineProperty(). This method accepts three arguments. One: the object that owns the property, two: the property name and three: a property descriptor object. Below is a code block to better explain things.

        const person ={
              name:"Bob"
        }
        Object.defineProperty(person,"name",{
            enumerable:false,
            configurable:false
        })
    
  • The code above has made the name property on the person object nonenumerable and nonconfigurable. What this means is that we can't loop over it and we can't change it, even using the delete operator on it would not work.

Data Property Attributes

  • Along with [[Enumerable]] and [[Configurable]] data properties have two additional attributes that accessors do not. The first one being [[Value]], which holds that properties value and it gets filled automatically when a property is first created. The second attribute is [[Writable]] which when set to true indicates whether a property can be written to. All properties are writable unless otherwise specified. The code block below two pieces of code that are equivalent

         const person ={
            name:'Bob' 
         }
    
        Object.defineProperty(person,"name",{
             value:'Bob',
             enumerable:true,
             configurable:true,
             writable:true
        }
    
  • Normally JavaScript does all of that extra stuff for us but Object.defineProperty() allows us to have a finer level of control. Also, it should be noted that if you only define one attribute all the others will default to false.

Accessor Property Attributes

  • Because the is no value stored for accessor properties, there is no need for the [[Value]] or [Writable]]. Instead accessors have [[Get]] and [[Set]] which contain the getter and setter functions.

  • We can also use Object.defineProperty() to define accessor properties. This gives us the advantage of being able to add getters and setters automatically, if we wanted to.

        let person ={
            name:"Bob"
        }
    
        Object.defineProperty(person,"name",{
                get:function(){
                  console.log('reading the name')
                  return this.name
                },
                set:function(){
                  console.log('setting the name value')
                },
                enumerable:true,
                configurable:true
       }
    
  • As you can see from the code block above using Object.definePropery() is also the exact same as using it with data properties. Please note that setting enumerable and configurable is allowed because they are the attributes that are shared with data properties.

Conclusion

  • This marks the end of part 3 of my object oriented programming in JavaScript. The next post will be on constructors and prototypes. If you have any opinions on this post please let me know on twitter

Top comments (3)

Collapse
 
stereobooster profile image
stereobooster
const person = {
  name="Bob" // <-- data property
};
Enter fullscreen mode Exit fullscreen mode

Uncaught SyntaxError: missing : after property id

Collapse
 
theplebdev profile image
Tristan Elliott • Edited on

Thank you for notifying me. I see I made that error in two places. The correct syntax is

const person ={
name:"Bob"
}
I have made the appropriate changes.

Collapse
 
codefinity profile image
Manav Misra

Love the (DEEP END WARNING) ! 😃 〰️

Stop by this week's meme thread!

Tech CEOs