April 6, 2020
Estimated Post Reading Time ~

Javascript Objects

One can think of a javascript object as containers with collections of data in it. Each data within the collection has a property name or key, with an assigned value (key-value pairs) to it. These values can be of primitive types, functions, objects, etc. When the value of a pair is a function, we call this a method. Behind the scenes, when an object is created and properties and values/methods are added to it, the object stores references to these for later access. This means that objects can store references to other objects.

There are a few ways we can create objects in javascript. We can use object literals, constructor functions, the Object.create method and we can use ES6 classes to create objects as well.

The simplest and most common way to create objects in javascript is to use an object literal var book = {};

We use curly braces to create a brand new object. A new address is created for this object behind the scene. We can set up key/value pairs like this 
var book = { 
title : 'The hidden Universe', 
author: 'Konstantin'
};

We have added two properties within the curly braces(title and author). An object can hold different data types, strings, boolean values, functions, etc. Another way we can create our book object is to use the new keyword 

var book = new Object();
book.title = 'The hidden Universe';
book.author = 'Konstantin';

This does the same thing as our book object literal(which is shorthand). It creates a new object and adds properties to it. We use dot notation to add properties using the new operator. So book.title will add a property called title to the book object. We can retrieve object property values also by using the dot notation. If we console.log the statements below we will get the values assigned to the properties. 
console.log(book.title);
console.log(book.author);

We don't always have to use the dot notation to add properties. Sometimes we want to add a property name that may be dynamic(thus we don't know what the name would be). We use the bracket notation in this case. 

book['title']book['author']

Notice that the property name is now written as a string. So we are able to add property names that have spaces in them, eg. book[‘My Name’]. This would be a valid javascript name and would throw an error if you tried setting that name as a property using the object literal way.

Using the book object defined earlier (with object literals), we can add more properties to it without having to directly add it to the object literal. 

book.publishDate = 'Jan 1 2016';book.pageCount = 300;

This dynamically adds a publishDate and a pageCount property to our object. By doing this our object literal now looks like this:

var book = {
title : 'The hidden Universe',
author: 'Konstantin',
publishDate: 'Jan 1 2016',
pageCount: 300
};


The new properties are now dynamically added. What if you want to add methods to an object? We do it the same way as adding properties 

book.printPage = function(){ 
console.log('printing book page');
}

What is happening here is we are attaching an object to the property name (the key is printPage and value is the function). Functions in javascript are objects. To call this function we also use the dot notation and invoke the 

function using ( ); 
book.printPage();

We could also have easily added this function to the object literal manually 

var book = { 
title : 'The hidden Universe', 
author: 'Konstantin', 
printPage : function(){ 
console.log('printing book page'); 
}
};

Next, let's add 2 array properties editions and translators. One will have an array value, the other an array of objects.

var book = {
title: 'The hidden Universe',
author: 'Konstantin',
printPage : function(){
console.log('printing book page');
},
editions: ['1', '2', '3'],
translators : [
{
publisher: 'Unipub A',
language: 'English'
},
{
publisher: 'Unipub B',
language: 'arabic'
}
]
};


We can retrieve values from the array or array of objects using the dot notation. 

console.log( book.editions[1] );console.log( book.translators[1].language );

It is important to have a mental note, that when we add data to an object, what happens is that data is stored somewhere in memory NOT in the object(syntactically it looks like we are writing on the object). The object only has reference to that data. We will see later on that when we delete a property from an object, even though it's removed it still exists. I will explain more in the next section.

Dynamically adding & removing properties
What if we want to add objects in a dynamic manner. We can create a function on the fly using dot notation or create a method on our book object that will add these new objects when called. Let's take a look at how we might do this. Let's create a 

new book Object var book = { 
tarzan : { 
publisher: "Publ A", 
author: "Author A", 
pages: 300
}, 
cinderella : { 
publisher: "Pub B", 
author: "Author B", 
pages: 400
}, 
"hidden universe" : { 
publisher: "Pub C", 
author: "Konstantin", 
pages: 1000
}
};

Here is our book object. How can we dynamically add a new book to it? Lets first add a method to our object that will do this for us. we will call it addBook.

var book = {
tarzan : { publisher: "Pub A", author: "Author A", pageCount: 300},
cinderella : { publisher: "Pub B", author: "Author B", pageCount: 400},
"hidden universe" : { publisher: "Pub C", author: "Konstantin", pageCount: 1000},
addBook : function(name, publisher, author, pageCount) {
this[name] = {publisher: publisher, author:author, pageCount};
}
};


book.addBook('JS Objects', "Publisher Z", "Konstantin", 300);
console.log(book);


Can you figure out what the addBook function is doing? It's an anonymous function that takes 4 parameters and constructs an object. That object is assigned to a property name equal to the name param passed to it. This keyword will always refer to the owner object of the function in which the this is used. So this[name] will look to see if that property exists. If it doesn’t, it will add it to the object. We could have created this method outside of the book: 

function addBook(bObject, name, publisher, author, pageCount) { 
bObject[name] = {
publisher: publisher, 
author:author, 
pageCount};
}
addBook(book, 'JS Objects', "Publisher Z", "Konstantin", 300);
console.log(book);

Notice that because we are NOT in the book object (function is defined outside), we had to pass in the object to which to add the new property/value. bObject is the book object and is passed as part of the parameters. If we console.log this we see that the new book property has been added with its value.

Deleting Object Properties
Deleting object properties might not be what you would expect, so it is worth speaking about it here. Taking our book object, let's add a publisher's property to it. var book = { 
title : 'The hidden Universe', 
author: 'Konstantin', 
publishers: [ "Publisher A", "Publisher B" ]};

Now that our publisher's array is added, we will be able to access that property using dot syntax, like this 

console.log( book.publishers[0] );

To delete a property on an object, we use the delete keyword followed by the property name. So to delete, title, author or publishers, we can do this delete 

book.title;delete book.author;delete book.publishers;

Now if we tried to retrieve the title in our console, we will get undefined, because it was deleted. 

console.log( book.title );

Now, something interesting is happening that needs further investigation, assuming we never deleted the publisher's property, let's assign it to a variable before deleting it. 

var myPublishers = book.publishers;console.log(myPublishers);

the contents of publishers now exist in the myPublishers variable, and our console.log outputs the content of the publisher's array. Now, let's delete myPublishers and try to see its values. 

delete book.publishers;console.log(book.publishers);console.log(myPublishers);

book.publishers is gone and returns undefined. But notice that myPublishers still has a reference to the array. When you use the delete keyword on an object, you are only deleting the property on the object not where it's saved in memory! This can trip a lot of developers and is important to note.

You should also know that when you delete a property on an object, javascript ALWAYS returns true even if the property does not exist. Weird huh? Well, think of it this way, if you say delete.myPreciousProperty, javascript looks in the object and verifies that property really isn't there, and returns true. Be careful when using delete, but most importantly understand how it works.

Now that we understand how delete works, lets dynamically remove a property. We will define a method in our book object called removeBook.

var book = {
tarzan : { publisher: "Pub A", author: "Author A", pageCount: 300},
"hidden universe" : { publisher: "Pub B", author: "Author B", pageCount: 1000},
addBook : ....,

removeBook : function(name) {
var temp = this[name];
delete this[name];
return temp;
}

};


Let see what this method is doing. The temp variable holds a reference to the object we want to delete. This way we still have access to it outside of our book object just incase we want to do some additional stuff to it. Best way to understand this is to see it in code 

var myRemovedBook = book.removeBook("tarzan");console.log(book);
console.log(myRemovedBook); 
//{ publisher: 'Publisher A', author: 'Author A', pageCount: 300 }

What happens now is that tarzan is completely removed from the book object(in our first console). But don't forget its only the property that is removed, the object still lives in memory. The myRemovedBook variable now points to it. You can see from the console that tarzan is gone from the book object BUT myRemovedObject still holds the available object. 

Those of you with a careful eye might notice that the console.log for the myRemovedBook does not include the tarzen name, just the object's value! We may not want this. How to we hold onto that name in our removeBook method? Let's add one line to save the name.

var book = {

tarzan : { publisher: "Pub A", author: "Author A", pageCount: 300},
"hidden universe" : { publisher: "Pub B", author: "Author B", pageCount: 1000},
addBook : ....,

removeBook : function(name) {
this[name].name = name; //<-
var temp = this[name];
delete this[name];
return temp;
}
};


Look crazy huh? It's not that complex. The this[name] finds a property name on the object (eg. tarzan). We attach the name we want to pass. The second name will set the name property of the object. Remember that objects have a property name and value. We use the second name to set/assign the name property of the new object we are trying to remove (which we later set as the temp variable). So temp will have the name of tarzan. When we return temp, not only do we get the value, we get the name as well! Note: the second name(this[name].name) is NOT the same as the functions passed in parameter. Let do a little recap. 

We have a function (removeBook) that gets passed a name parameter. Simple to understand that. Within this function we assign this[name].name (which I explained earlier) TO that named parameter passed into the function. So note that even though we have 3 name properties being used here, they are not all the same.

Constructor functions
Now, what if you wanted to create multiple book objects like we do in static languages like C or C++. We use a constructor function with the new keyword. A constructor function is used to “construct” / create objects. A constructor function is basically a function. However, it is how you use this function that makes it unique. To construct objects from this function we use the new keyword followed by the function name. Let's create a Book constructor 

function Book(title, author) { 
this.title = title; 
this.author = author;
}

This is just a basic function that adds properties to the object. The this keyword refers to an object and is the object that is executing the current bit of code. By default, this keyword is the global object. In a web browser, it is the window object. A constructor function is used with the new keyword to create objects. 

var book = new Book('The hidden Universe', 'Konstantin');

The new keyword creates a new javascript object, sets the context of ‘this’ to that new object, and then calls the Book function. When the function is called it returns ‘this’ (which will be Book). It also sets the object to delegate to Book.prototype. I explain this prototype later.

Let's look at yet another way to create objects in javascript using Object.create. We have looked at using object literals and constructor functions with the new keyword. You should know that both these methods are syntactic sugar for Object.create (which is doing all the job behind the scene). The general definition for 

Object.create is as follows Object.create(proto [, propertiesObject ])

The first argument is the prototype to extend. Now let's create a new book object 

var book = Object.create(Object.prototype, { 
title: { 
value: 'The hidden Universe', 
enumerable: true; 
writable: true; 
configurable: true; 
}, 

author: { 
value: 'Konstantin', 
enumerable: true; 
writable: true; 
configurable: true; 
}
});

Within the Object. create, we pass in the object that will become the prototype of the object we are creating. We also define prototypes properties. So what is this prototype? All objects have a prototype property. Just like in our book object, we have a title and author property, every object has a property automatically added to it called prototype. This prototype property is only a reference to another object. 

We will be talking more about prototypes in another tutorial, but this object is very important. What happens is, if you ask javascript for property value and it does not find it, it will search its prototype object for that property. If it exists there, that value will get returned. Again this tutorial will not go deep into prototypes, but it is worth having an idea what it is for now. Be sure to read the tutorial link just provided.

One should note, that when we use constructor functions with the new keyword or use object literals, all this Object.create magic happens in the background for us. If you ask me, it might be quite tedious to use this to create syntax on a daily basis. Using object literals or constructor functions we can create our objects more easily, then if we want more control, we can use object properties to do that. We will get deeper with that topic soon.

The ES6 specification now includes functionality for object creation using a class keyword. This is quite similar to what you might see in other languages. Though this is nice, know that its syntactic sugar around the object. create method 

class Book { 
constructor(title, author) { 
this.title = title; this.author = author; 
//method 
printPage(){ 
console.log('printing book page'); 
var book = new Book('The hidden Universe', 'Konstantin'); 
book.printPage();

Instead of using the constructor function, we use the new class keyword and defined our constructor function within it. We define 2 properties and a method and instantiated it like we have done before. This way might appeal to programmers coming from statically typed languages. You instantiate it the same way as you would with constructor functions.

OBJECT PROPERTIES – BEYOND THE BASICS
Let us look more into what you can do with object properties. Earlier on we saw how you can set object properties. But we can actually do more than meets the eye.
We learned that you can set or get an object's properties by using the bracket/dot notation. For example, we got the title of the book using the syntax book['title'];

There is more we can do with bracket notation that needs to be said. For example what if we need to set a property name that was not a valid identifier? For example, you would get an error if you set a name like ‘book format’. Like this 

var book = { book format : 'PDF'};

We would get an error because of space in-between. It's not a valid identifier. However using bracket notation, we can set ‘book format’ on the object without 

Error 
book['book format'] = 'PDF'; or var book = { 'book format' : 'PDF' }

This is valid syntax because the bracket notation has a string identifier. Why would you want to use the bracket syntax over the dot notation? Well if you wanted to create an object out of values being entered by a user or set properties that are not valid identifiers then bracket notation is the way to go.

Property Descriptor
Object properties can also be more than just a name and a value. Every property has a property descriptor that lets you see the attributes of the property. Using our book object, we can get its property descriptor like this 

console.log( Object.getOwnPropertyDescriptor(book, 'book format') );

This outputs 
value: 'PDF', 
writable: true, 
enumerable: true, 
configurable: true
}

Not only do we see that the book format property has a value, but it also has other attributes (writable, enumerable and configurable). Let's take a closer look at what these as they help us to take our knowledge on objects to another level.

Writable property
The writable property defines whether the property's value can be changed from its initial value. To change any property attribute we use the Object.defineProperty method like this Object.defineProperty(book, 'book format', {writable:false});

Try changing the name of the book format 
book['book format'] = "Epub"

Run this in a browser making sure strict mode is turned on. You get this Error
“Cannot assign to read-only property ‘book format’ of #<Object>”
Note if you don't run in strict mode your program will silently fail, which is not a good thing. Imagine trying to change a property that silently fails. This will be really hard to debug.

What if we make an object property none writable. for example, 

var book = { 
author : { 
firstname: 'Konstantin', 
lastname: 'Addaquay' 
}
};

lets make this author property none writable 
Object.defineProperty(book, 'author', {writable:false});

Let's try to change the author 

book.author = "kofi";

This gives us an Error
“Cannot assign to read-only property ‘author’ of #<Object>”
Which is exactly what we want. But an interesting thing happens (if you remember our discussion on object references you probably have an idea what I am going to talk about next). We can change the firstname property still by doing this 

book.author.firstname = "Jonas";
console.log(book.author);

So even though the author's property is read-only, we were able to change the value of a property that the author's property was pointing to. Since the author is just a pointer, making it read-only prevents that pointer NOT to be changed. If you really want to prevent the object from being changed in its entirety we can use 

Object.freeze Object.freeze(book.author);

With this in place, we cannot change the author's property. It is now read-only in addition to the author's properties. The thing to TAKE HERE IS IF YOU MAKE A PROPERTY READ ONLY THAT HAS AN OBJECT VALUE YOU WILL NEED TO FREEZE THE OBJECT IN ORDER TO PREVENT IT FROM BEING CHANGED.

Enumerable property
Going back to our book object 

var book = { 
title : 'The hidden Universe', 
author : { 
firstname: 'Konstantin', 
lastname: 'Addaquay' 
}
};

Looping through object properties is called enumeration. You may hear other say iteration as well. Let's look at its syntax. 

for (var propName in book){ 
console.log(propName);
}

Before we dive deeper into the enumerable property, let's look a little bit closer at enumeration. We use a for-in loop to enumerate objects' properties. The var propName is just a variable we create. You can name it anything you want, but try to be descriptive as this variable holds the property name or key of the current item during the loop. In the above example, our console will output the title and author. Because these are the keys or properties in our object. Notice that objects don't have a length property, so we cant use it in a loop to determine how many properties exist.

Another way one might get objects keys is to use the keys method 

console.log(Object.keys(book));

This will also output the property's names. This method, however, is a little limiting because we cannot get the property values. Getting back to our iteration, we can grab the property values using the bracket notation 

for (var propName in book){ 
console.log(propName + ": " + book[propName]);
}

In each iteration, we look at the value for the property name we are currently looping on( book[propName] ) and display it. Let's look at an interesting scenario. Let us re-define the book object and iterate through it 

var book = { 
tarzan : { publisher: "Pub A", author: "Author A", pageCount: 300}, 
"hidden universe" : { publisher: "Publ B", author: "Konstantin", pageCount: 1000}, removeBook : function(name) { 
//do something 

}; 
//lets iterate 
for ( var propName in book ) { 
console.log(propName); 
}

Notice that in our console.log returns has removeBook is added. What if you only wanted to get the book properties and not methods on the object. How do we determine which properties are actually books? What we can do here is during our loop, we can check each property’s value, to see if it has an author. Let's see how 

var bookCount = 0;
for ( var key in book ) { 
if( book[key].author ) { 
bookCount++; 
}
}
console.log(bookCount);

Our console now returns 2. During the loop, we check if the current property we are on has the name of the author. We can even take this further by counting only authors who are named Konstantin. Like this 

var bookCount = 0;
for (var key in book) { 
if(book[key].author === "Konstantin") { 
bookCount++; 
}
}
console.log(bookCount);

This is the power of enumeration. Since methods on our object(like removeBook) will NOT have an author property assigned to, it is ignored in our loop counter.

Sometimes when we iterate through objects its possible to get unexpected results as the object could be inheriting from other objects. This means it can have more properties than needed. In our enumeration, we can use a method called hasOwnProperty to check to see if the current object has that property(and that it's not being inherited). If it does then it will proceed. We will look more into javascript inheritance and prototypes in a tutorial after this. Let continue with where we left off, the enumerable property.

The enumerable property only means you can loop over properties in that object. By default, all objects have an enumerable property of true. Let makes enumerable false for the author's property. 

Object.defineProperty(book, 'author', {enumerable:false});

Now try to enumerate the object properties 

for (var propName in book){ 
console.log(propName + ": " + book[propName]);
}

You notice the only the title was enumerable. The author does not get logged in the console. Another use of the enumerable property, when set to false, is so that the property does not show up in the object keys. You should also note that setting enumerable to false will affect JSON serialization, ie that property won't show for e.g when you use JSON.stringify(book). I will touch on JSON later on in this post. Finally setting enumerable to false does not prevent a user from using the bracket notation to see the properties. You can do this 

console.log( book['author'] ); //user can see author with this

Configurable property

This property locks down a property to prevent certain attributes from being changed. It also prevents the property from being deleted from the object. 

Object.defineProperty(book, 'author', {configurable:false});

Now that the author's property configurable has been set to false, trying to set any attribute for eg the enumerable property to false will fail. You will get an Error "Cannot redefine property: author"

You can, however, change the writable property without getting an error 

Object.defineProperty(book, 'author', {writeable:false});

Finally, when the configurable property is set, you cannot delete a property. doing this 

delete book.author;

you will get an error “Cannot delete property ‘author’ of #<Object>”
Three things are affected when you make a property non configurable.
1) If configurable is false, you cannot change the enumerable attribute
2) You cannot change the configurable attribute
3) You cannot delete the property

Getters and Setters are attributes on a property that allows you to set and get the value of a property using a function. Let's look at an example. 

var book = {
 author : { 
firstname: 'Konstantin', 
lastname: 'Addaquay' 
}
};

Object.defineProperty(book, 'fullName',{ 
get : function(){ 
return this.author.firstname + ' ' + this.author.lastname; 
}, 

set : function(value){ 
var nameparts = value.split(" "); 
this.author.firstname = nameparts[0]; 
this.author.lastname = nameparts[1]; 
}
}); 
console.log(book.fullName); 
We can also set the fullname like this 
book.fullName = "John Doe";

Javascript Object Notation – JSON
I thought it would be nice to talk about JSON. It is inspired by object literal syntax in javascript. Note however that they are not the same. JSON is a format used to send data across the internet these days. It used to be XML. But due to XML’s verbosity, we came up with a new format to send data across the wire. So the javascript literal format looked like an appealing way to send data. It looks very simple. Here is a sample 

"firstname" : "konstantin", 
"lastname" : "addaquay", 
"isDeveloper": true
}

JSON is really a subset of the object literal syntax. See how closely it resembles the JS object literal we saw earlier? JSON, however, has stricter rules. Notice the quotes that surround the property names. This is needed to make your JSON valid, however, you don't need quotes when you use JS object literals(even though you can). Note JSON is not Javascript. Because of this, you can use some javascript functionality to get JSON data and convert that JSON to a validate object (so you can use that data in your application). You can look at sample JSON here.

If we get JSON data in our app, we can convert that string using the parse method in javascript.

var myDATA = JSON.parse('{"firstname":"konstantin","lastname":"addaquay","isDeveloper":true}');

Doing this will convert that data string to a valid javascript object. Isn't that cool? We can do the reverse. We can take a javascript object and convert that to a valid JSON string using the stringify method. 

var book = { 
author : { 
firstname: 'Konstantin', lastname: 'Addaquay' 
}
}; 
var myString = JSON.stringify(book);

myString now gets the JSON format assigned to it. So that's it with JSON. Please be sure not to confuse it with object literals.



By aem4beginner

No comments:

Post a Comment

If you have any doubts or questions, please let us know.