JavaScript objects are containers that hold zero or more properties, where each property is a name/value pair. The value of these properties can be either data or functions. Property functions are known as methods and allow us to modify data properties of an object.
Object-oriented programming in JavaScript is class-free -- objects are not created by defining a common class or an object-template; instead, they are created using another object as a template.
The syntax for defining a JavaScript object is simple. For each property, its name should be separated from its value using a colon (":"). The object definition encloses all of its name/value properties within braces. As an example, if were to define an object, "objDragon", holding a property, "name" with a value of "Kilgharrah", then we can do that as: 'var objDragon = {name: "Kilgharrah"};'.
JavaScript provides two methods for accessing properties of an object. The first method uses the "." (single dot) operator; thus, to access the "name" property of "objDragon", we can use "objDragon.name". The second method treats an object as an associative array and passes the property as a key to the array: objDragon["name"]. Note that object properties can not be accessed directly outside of their object context and so we must provide the name of the object before accessing it.
JavaScript objects are non-primitive variables; being non-primitive, they are mutable. This means that we can update the value of properties, as and when needed. Further, we can also add/delete properties on the fly.
To update the value of an existing property, we can simply reassign a new value to it; the statement, 'objDragon.name = "Glaurung";' would update the value of "name" property from "Kilgharrah" to "Glaurung". To add a new property, we can assign something to the new property, as if it already existed and we are merely modifying it. Thus, 'objDragon.place= "Camelot";' would add a new property, "place" to "objDragon". Lastly, to delete an existing property, we can use the delete operator -- "delete objDragon.place" would delete "place" property.
Running a typeof operator for an object returns the string "object". Thus, "typeof objDragon" would return the string "object".
Next, we provide a simple example that defines an object, "objFable" with two properties: "name" and "dragon". After defining the object, this example updates, adds, and deletes its properties. This example (output is shown in comments) demonstrates that we can dynamically add a new property ("description") or delete an existing one. Lastly, trying to access a deleted property simply returns "undefined".
<!doctype html> <html> <div id="idDiv"></div> <script type="text/javascript"> // Get a handle of the div element. var elem = document.getElementById("idDiv"); // Define an object. var objFable = {name: "Farmer Giles of Ham", dragon: "Chrysophylax"}; // Accessing properties of objFable. elem.innerHTML += "<br>Fable name: " + objFable.name; elem.innerHTML += "<br>Dragon name: " + objFable.dragon; // Change an existing property of objFable. objFable.dragon = "Chrysophylax Dives"; elem.innerHTML += "<br>(After update) Dragon name: " + objFable.dragon; // Dynamically add a property to objFable. objFable.description = "A Medieval Fable"; elem.innerHTML += "<br>Fable description: " + objFable.description; // Next, let us delete a property. delete objFable.description; // Accessing a deleted property will return "undefined". elem.innerHTML += "<br>Fable description: " + objFable.description; </script> </html>
Here is the output when we save the above example in a file and access it using a browser:
Objects are fairly versatile in terms of what they contain; they can even contain other objects as their property values.
Let us modify the earlier objFable so that, it now includes another object (as property "characters"). Further, we also add a new property, "printFable" that is actually a method. This method prints properties of the object using a for/in loop. While iterating in the loop, this method uses typeof operator to determine the type of the property and if the typeof returns "function", then the loop skips those properties, since there is no point in printing functions. Additionally, if the typeof returns "object", then it means that this property is an object and so printFable() uses another for/in loop to print the child object.
<!doctype html> <html> <div id="idDiv"></div> <script type="text/javascript"> // Get a handle of the div element. var elem = document.getElementById("idDiv"); // Define an object. var objFable = { name: "Farmer Giles of Ham", dragon: "Chrysophylax", characters: {protagonist: "Giles, the Farmer", antagonist: "Chrysophylax, the Dragon"}, printFable: function () { // This is a method. for (var item in this) { if ((typeof this[item]) == "function") continue; // Skip functions. if ((typeof this[item]) == "object") { // Print Child objects. elem.innerHTML += item + ":"; for (var internalItem in this[item]) { elem.innerHTML += "<br>" + internalItem + ": "; elem.innerHTML += (this[item])[internalItem]; } } else { elem.innerHTML += item + ": " + this[item] + "<br>"; } } }, }; // Let us print the object objFable.printFable(); </script> </html>
We provide the output (as seen on a browser) when we run the above example.
name: Farmer Giles of Ham dragon: Chrysophylax characters: protagonist: Giles, the Farmer antagonist: Chrysophylax, the Dragon
In JavaScript, we can copy an object from another object using a simple assignment. Thus, if we were to make a copy of the objFable object, then we can do so using: "copyObjFable = objFable;". JavaScript copies objects using reference instead of making an actual copy. This approach is more efficient since it is cheaper to return a reference of the object than to make a copy of the entire object.
However, there is one important caveat! If we modify the behavior of the object via the reference copy, then we would end up modifying the original object as well. This is because with reference, the copy is just a "link" to the original object and thus, modifying one would automatically modify the other.
Let us demonstrate this behavior using the below-provided example. We take the previous "objFable" object and then make a copy of it. When we modify the property values for the copied object, then the original object also gets modified.
<!doctype html> <html> <div id="idDiv"></div> <script type="text/javascript"> // Get a handle of the div element. var elem = document.getElementById("idDiv"); // Define an object. var objFable = { name: "Farmer Giles of Ham", dragon: "Chrysophylax", printFable: function () { // This is a method. var i = 0; for (var item in this) { if ((typeof this[item]) == "function") continue; //Skip functions. if ( i != 0) {elem.innerHTML += ", ";} elem.innerHTML += item + ": " + this[item]; i++; } }, }; // Let us print the object. objFable.printFable(); // Prints "name: Farmer Giles of Ham, dragon: Chrysophylax" // Let us make a copy. copyObjFable = objFable; // Let us modify the new copy and print it. copyObjFable.name = "The Hobbit"; copyObjFable.dragon = "Smaug"; copyObjFable.printFable(); // Prints "name: The Hobbit, dragon: Smaug". // Let us print the original object. objFable.printFable(); // Prints "name: The Hobbit, dragon: Smaug". </script> </html>
The above example shows that if we do need to create an independent copy of an object, then we are better off avoiding the reference method. One safe approach is to use the first one as a Prototype for the new object and then manually copy values from the original object to the new one; we will discuss prototypes and this approach shortly in a subsequent section.
Sometimes, it is more convenient to write a program such that it invokes a chain of methods, one after another. We can achieve this multiple invocations in one statement, as long as each method returns the object after its execution is complete. This is because if the returned value is an object itself, then we can to invoke the object's method once again on the return value. This technique is popularly referred to as Method Chaining.
Method Chaining is widely used in jQuery -- one of the JavaScript popular libraries.
Let us look at a simple example to understand method-chaining in more detail. This example (provided below) defines a simple object warlock that has three methods: summonTheDragon(), rideTheDragon(), and instructTheDragon(). Each of these methods return the "this" value which refers to the object being invoked that is object warlock.
<!doctype html> <html> <div id="idDiv"> </div> <script type="text/javascript"> // Get a handle of the div element. var elem = document.getElementById("idDiv"); // An object with three methods var warlock = { summonTheDragon: function () { elem.innerHTML += "Let me summon the Dragon <br>"; return this; }, rideTheDragon: function () { elem.innerHTML += "Let me ride the dragon <br>"; return this; }, instructTheDragon: function () { elem.innerHTML += "Let me instruct the dragon <br>"; return this; }, }; // Invoke methods in a chain. warlock.summonTheDragon().rideTheDragon().instructTheDragon(); </script> </html>
From the output (provided below), we can see that the invocation happens from left to right. The warlock object first invokes summonTheDragon() method and the summonTheDragon then returns the object warlock. Next, the chain invokes the rideTheDragon() followed by the instructTheDragon() method.
Let me summon the Dragon Let me ride the dragon Let me instruct the dragon
JavaScript objects are an important JavaScript construct -- virtually all non-primitive types like arrays, functions, Dates, Regular Expressions are objects. In this regard, JavaScript comes with a host of built-in objects that provide a plenty of options for applications to use them instead of writing their own custom objects. These built-in objects derive their behavior from their respective built-in prototypes.
This section describes some of the commonly used built-in objects: Array, String, Date, Number, and Boolean.
To define these objects, we can use the "new" keyword to create an instance of an object of these types; the "new" keyword invokes the constructor method defined by the respective prototype. Thus, to create an array, all we need to do: 'var a = new Array("Kilgharrah");'. This statement would invoke the constructor method provided by Array.prototype (the prototype of all Array objects).
Similarly, we can use Boolean object to define an object that holds a boolean value (true or false). We can invoke the Boolean constructor (made available by Boolean.prototype) to create an object that stores the current date. Another type of built-in object is that of Date and we can invoke the Date constructor (made available by Date.prototype) to create an object that stores the current date.
Some of these objects like String, Number, and Boolean are essentially a wrapper objects around their primitive counterparts: string, number, and boolean. These objects provide a host of methods that allow us to process the primitive value stored in these objects. Since the primitive types are immutable and offer limited capabilities, providing a built-in wrapper object significantly enhances their usability.
We provide a trivial example that invokes constructors for some of these built-in methods and then prints their value. We will revisit both Array and String objects later in this module.
<!doctype html> <html> <div id="idDiv"></div> <script type="text/javascript"> // Get a handle of the div element. var elem = document.getElementById("idDiv"); // Define an array. var a = new Array("Kilgharrah"); elem.innerHTML += a; // Prints "Kilgharrah". // Define a Boolean object. var b = new Boolean(true); elem.innerHTML += b; // Prints "true". // Define a Date object. var d = new Date(); elem.innerHTML += d; // Prints current date: "Sat Apr 07 2012 22:40:45 GMT-0700 (PDT)". // Define a String object. var s = new String("The wise dragon spoke to the wizard"); elem.innerHTML += s; // Prints "The wise dragon spoke to the wizard". </script> </html>
All of these prototypes come with a host of methods. If we wish to see the list of all methods published by a prototype, then we can use Object.getOwnPropertyNames() method. This method returns an array that holds all the properties published by the object. As an example, "Object.getOwnPropertyNames(Array.prototype)" would return an array holding all methods published by Array.prototype.