One can think of a javascript objects 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 setup key/value pairs like this
var book = {
title : 'The hidden Universe',
author: 'Konstantin'
};
We have added two properties with in 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 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 dont always have to use the dot notation to add properties. Sometimes we want to add a property name that may be dynamic(thus we dont 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:
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 (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, lets add 2 array properties editions and translators. One will have an array value, the other an array of objects.
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 its 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. Lets take a look at how we might do this. Lets 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.
Can you figure out what the addBook function is doing? Its 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. The 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 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, lets add a publishers property to it.
var book = {
title : 'The hidden Universe',
author: 'Konstantin',
publishers: [ "Publisher A", "Publisher B" ]
};
Now that our publishers 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 publishers property, lets assign it to a variable before deleting it.
var myPublishers = book.publishers;
console.log(myPublishers);
the contents of publishers now exists in the myPublishers variable, and our console.log outputs the content of the publishers array. Now lets 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 its 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 isnt 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.
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 dont 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 objects value! We may not want this. How to we hold onto that name in our removeBook method? Lets add one line to save the name.
Look crazy huh? Its 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 a 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 name 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. Lets create a Book constructor
function Book(title, author) {
this.title = title;
this.author = author;
}
This is just a basic function that adds properties on the object. The this keyword refers to an object, and is the object that is executing the current bit of code. By default, the 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 return ‘this’ (which will be Book). It also sets the object to delegate to Book.prototype. I explain this prototype later.
Lets 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 syntatic 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 lets 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 that 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 a 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 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 was 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 objects 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 the space in-between. Its 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, it also has other attributes (writable, enumerable and configurable). Lets 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 properties 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 dont run in strict mode your program will silently fail, which is not a good thing. Imagine trying to change an 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});
Lets try to change the author
book.author = "kofi";
This give 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 property is read only, we were able to change the value of a property that the author property was pointing to. Since 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 property. It is now read only in addition to the author 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. Lets look at its syntax.
for (var propName in book){
console.log(propName);
}
Before we dive deeper into the enumerable property, lets 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 title and author. Because these are the keys or properties in our object. Notice that objects dont 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 properties 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. Lets 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. Lets 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 a name of 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 its 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 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 only title was enumerable. 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 wont 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 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 allow you to set and get the value of a property using a function. Lets 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 dont 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. Isnt 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 thats it with JSON. Please be sure not to confuse it with object literals.
Whats Next
Whew, another long post huh? Well i feel this is most of what you need to know about javascript objects. Yes there is more to objects, like learning about Prototypes and Prototypal inheritance. But THAT is our next topic. If you feel there is something about objects that i missed, do leave me a comment and i will be sure to modify this post. I hope this becomes someones go-to reference for Javascript Objects. Thanks for reading. Feel free to reach out on twitter as well ( @scriptonian ) if you have any questions.
Thanks for your post!! There is a misspelling after Konstantin and it throws an error in the console.
var book = {
title : ‘The hidden Universe’,
author: ‘Konstantin’,
publishers: [ “Publisher A”, “Publisher B” ]
};
Great catch Selma… it was a ’ instead of ‘… but its fixed now! thank you so much 🙂
Thanks for the article…pretty comprehensive and you point out a lot of subtle but important points….good stuff.
Just wanted to point out a mistake….In your “Deleting Objects” section (last sentence) you stated: “Note: the second name(this[name.name]) is NOT the same as the functions parameter (the third name is). ”
Two points:
1) I think you meant this[name].name NOT this[name.name];
2) It feels like this statement could use a bit more of an explanation because it’s not immediately obvious or intuitive. Just my opinion.
Cheers
Hi Jet! thanks for reading this post 🙂 Yes you are right, it was a typo and i just fixed it:-) Thank you for pointing it out. I also expanded a little bit as you asked… let me know if its better (if not will re-write that paragraph later on tonight).