JavaScript’s core, and most often used, and most fundamental data type is the Object data type. JavaScript has one complex data type, the Object data type, and it has five simple data types:
Note that these simple, primitive, data types are immutable, cannot be changed, while objects are mutable, can be changed.
An object is an unordered list of primitive data types, and sometimes reference data types, that is stored as a series of name-value pairs and each item in the list is called a property.
Consider this simple object:
var firstObject = {
firstName: "Henrik",
favouriteAuthor: "John",
}
Think of an object as a list that contains items, and each item, a property or a method, in the list is stored by a name-value pair. Property names in the example above are firstName and favoriteAuthor and the values are “Henrik” and “John”. Property names can be a string, or a number, but if the property name is a number, it has to be accessed with the bracket notation.
Here is an example of objects with numbers as the property name:
var ageGroup = { 30: "Children", 100:"Very Old" }
// This will throw an error
console.log(ageGroup.30)
// This is how you will access the value
// of the property 30, to get value "Children"
console.log(ageGroup["30"])
// It is best to avoid using numbers as property names.
As a JavaScript developer you will most often use the object data type, mostly for storing data and for creating your own custom methods and functions.
One of the main differences between reference data type and primitive data types is reference data type’s value is stored as a reference, it is not stored directly on the variable, as a value as the primitive data types are.
For example:
// The primitive data type String is stored as a value in the object data property name
var person = { name: "Tiger" }
var anotherPerson = person // anotherPerson = the value of person
person.name = "Woods" // value of person changed
console.log(anotherPerson.name) // Tiger
console.log(person.name) // Woods
In this example, we copied the person object to another Person, but because the value in person was stored as a reference and not an actual value, when we changed the person.name property to “Woods” the anotherPerson reflected the change because it never stored an actual copy of its own value of the person’s properties, it only had a reference to it.
Each data property, object property that store data, has not only the name-value pair, but also 3 attributes that are set to true by default:
Note that ECMAScript 5 specifies accessor properties along with the data properties noted above, and the accessor properties are functions, getters and setters.
These are the two common ways to create objects,
The most common and, indeed, the easiest way to create objects is with the object literal described here:
// This is an empty object initialized
// using the object literal notation
var myBook = {}
// This is an object with 4 items, again using object literal
var lemon = {
color: "yellow",
shape: "round",
sweetness: 1,
howSweetAmI: function () {
console.log("Hmm Hmm Good");
}
}
The second most common way to create objects is with Object constructor. A constructor is a function used for initializing new objects, and you use the new keyword to call the constructor.
var orange = new Object()
orange.color = "orange"
orange.shape= "round"
orange.sweetness = 5
orange.howSweetAmI = function () {
console.log("Hmm Hmm Good and Healthy")
}
While you can use some reserved word such as “for” as property names in your objects, it is wise to avoid this altogether. Objects can contain any other data type, including Numbers, Arrays, and even other Objects.
For simple objects that may only ever be used once in your application to store data, the two methods used above would suffice for creating objects. Imagine you have an application that displays fruits and detail about each fruit. All fruits in your application have these properties:
It would be quite tedious and counterproductive to type the following every time you want to create a new fruit object.
var mangoFruit = {
color: "yellow",
sweetness: 8,
fruitName: "Mango",
nativeToLand: ["South America", "Central America"],
showName: function () {
console.log("This is " + this.fruitName)
},
nativeTo: function () {
this.nativeToLand.forEach(function (eachCountry) {
console.log("Grown in:" + eachCountry)
});
}
}
If you have 10 fruits, you will have to add the same code 10 times and, what if you had to make a change to the nativeTo function? You will have to make the change in 10 different places. Now extrapolate this to adding objects for members on a website and suddenly you realized the manner in which we have created objects so far is not ideal objects that will have instances, particularly when developing large applications. To solve these repetitive problems, software engineers have invented patterns, solutions for repetitive and common tasks, to make developing applications more efficient and streamlined.
Here are two common patterns for creating objects.
function Fruit(theColor, theSweetness, theFruitName, theNativeToLand) {
this.color = theColor
this.sweetness = theSweetness
this.fruitName = theFruitName
this.nativeToLand = theNativeToLand
this.showName = function () {
console.log("This is a " + this.fruitName)
}
this.nativeTo = function () {
this.nativeToLand.forEach(function (eachCountry) {
console.log("Grown in:" + eachCountry)
})
}
}
With this pattern in place, it is very easy to create all sorts of fruits. Thus:
var countries = ["South America", "Central America", "West Africa"]
var mangoFruit = new Fruit("Yellow", 8, "Mango", countries)
mangoFruit.showName() // This is a Mango.
mangoFruit.nativeTo()
// Grown in:South America
// Grown in:Central America
// Grown in:West Africa
var apple = new Fruit ("Green", 5, "Apple", ["United States"])
apple.showName() // This is an Apple.
If you had to change the showName function, you only had to do it in one location. The pattern encapsulates all the functionality and characteristics of all the fruits in by making just the single Fruit function with inheritance.
An inherited property is defined on the object's prototype, for example;
someObject.prototype.firstName = “Henrik”
An own property is defined directly on the object itself, for example;
var aBanana = new Fruit()
aBanana.bitter = “some value”
Now we define the bitter property directly on the aBanana object. Because we define the bitter property directly on the aBanana object, it is an own property of aBanana, not an inherited property.
To access a property of an object, we use object.property, for example;
console.log(aBanana.bitter) // “some value”
To invoke a method of an object, we use object.method(), for example: First, lets add a method
aBanana.printStuff = function () {
return “Printing”
}
Now we can invoke the printStuff method:
aBanana.printStuff();
function Fruit() {}
Fruit.prototype.color = "Yellow"
Fruit.prototype.sweetness = 7
Fruit.prototype.fruitName = "Generic Fruit"
Fruit.prototype.nativeToLand = "USA"
Fruit.prototype.showName = function () {
console.log("This is a " + this.fruitName)
}
Fruit.prototype.nativeTo = function () {
console.log("Grown in:" + this.nativeToLand)
}
This is how we call the Fruit() constructor in this prototype pattern:
var mangoFruit = new Fruit()
mangoFruit.showName() // Generic fruit
mangoFruit.nativeTo() // USA
The two primary ways of accessing properties of an object are with dot notation and bracket notation.
// We have been using dot notation so far in the examples above,
// here is another example again:
var book = {
title: "Heroes all",
pages: 280,
bookMark1: "Page 20"
}
// To access the properties of the book object
// with dot notation, you do this:
console.log(book.title) // Heroes all
console.log(book.pages) // 280
// To access the properties of the book object
// with bracket notation, you do this:
console.log(book["title"]) // Heroes all
console.log(book["pages"]) // 280
// Or, in case you have the property name in a variable:
var bookTitle = "title"
console.log(book[bookTitle]) // Heroes all
console.log(book["bookMark" + 1]) // Page 20
Accessing a property on an object that does not exist will result in undefined.
Objects have inherited properties and own properties. The own properties are properties that were defined on the object, while the inherited properties were inherited from the object’s Prototype object.
To find out if a property exists on an object, either as an inherited or an own property, you use the in operator:
// Create a new school object with a property name schoolName
var school = {
schoolName:"KTH"
}
// Prints true because schoolName is an own property on the school object
console.log("schoolName" in school) // true
// Prints false because we did not define a schoolType property
// on the school object, and neither did the object inherit a
// schoolType property from its prototype object Object.prototype.
console.log("schoolType" in school) // false
// Prints true because the school object inherited the toString
// method from Object.prototype.
console.log("toString" in school) // true
To find out if an object has a specific property as one of its own property, you use the hasOwnProperty method. This method is very useful because from time to time you need to enumerate an object and, you want only the own properties, not the inherited ones.
// Create a new school object with a property name schoolName
var school = {
schoolName: "KTH"
}
// Prints true because schoolName is an own property on the school object
console.log(school.hasOwnProperty ("schoolName")) // true
// Prints false because the school object inherited the toString method from
// Object.prototype, therefore toString is not an own property of the school
// object.
console.log(school.hasOwnProperty ("toString")) // false
To access the enumerable (own and inherited) properties on objects, you use the for/in loop or a general for loop.
// Create a new school object with 3 own properties:
// schoolName, schoolAccredited, and schoolLocation.
var school = {
schoolName: "KTH",
schoolAccredited: true,
schoolLocation: "Stockholm"
}
// Use of the for/in loop to access the properties in the school object
for (var eachItem in school) {
console.log(eachItem)
// Prints schoolName, schoolAccredited, schoolLocation
}
Properties inherited from Object.prototype are not enumerable, so the for/in loop does not show them. However, inherited properties that are enumerable are revealed in the for/in loop iteration. For example: Use of the for/in loop to access the properties in the school object
for(var eachItem in school) {
console.log(eachItem)
// Prints schoolName, schoolAccredited, schoolLocation
}
// Create a new HigherLearning function that the school
// object will inherit from.
function HigherLearning () {
this.educationLevel = "University"
}
// Implement inheritance with the HigherLearning constructor
var school = new HigherLearning ()
school.schoolName = "MIT"
school.schoolAccredited = true
school.schoolLocation = "Massachusetts"
// Use of the for/in loop to access the properties in the school object
for (var eachItem in school) {
console.log(eachItem)
// Prints educationLevel, schoolName, schoolAccredited, and schoolLocation
}
Since the “this” keyword in the HigherLearning Constructor points to the newly created object, in this case the school object, and therefore the educationLevel property will be created on the school object, then it follows that educationLevel is not really inherited from the Constructor, but rather, it is a property that is actually created (new property) on the school object upon invocation of said school object.
To delete a property from an object, you use the delete operator. You cannot delete properties that were inherited, nor can you delete properties with their attributes set to configurable. You must delete the inherited properties on the prototype object (where the properties were defined). Also, you cannot delete properties of the global object, which were declared with the var keyword. The delete operator returns true if the delete was successful. And surprisingly, it also returns true if the property to delete was nonexistent or the property could not be deleted (such as non-configurable or not owned by the object).
These examples illustrate:
var christmasList = {
lars:"Book",
tobbe:"sweater"
}
delete christmasList.lars; // deletes the lars property
for(var people in christmasList) {
console.log(people);
}
// Prints only tobbe
// The lars property was deleted
// returns true, but toString not deleted because it is an inherited method
delete christmasList.toString;
// Here we call the toString method and it works just fine—wasn’t deleted
christmasList.toString(); //"[object Object]"
To transfer your objects via HTTP or to otherwise convert it to a string, you will need to serialize it (convert it to a string); you can use the JSON.stringify function to serialize your objects.
Note that prior to ECMAScript 5, you had to use a popular json2 library (by Douglas Crockford) to get the JSON.stringify function. It is now standardized in ECMAScript 5. To Deserialize your object (convert it to an object from a string), you use the JSON.parse function from the same json2 library. This function too has been standardized by ECMAScript 5. JSON.stringify Examples:
var christmasList = {
lars:"Book",
lisa:"sweater",
lara:"iPad"
}
JSON.stringify(christmasList)
// Prints this string: "{"lars":"Book","lisa":"sweater","lara":"iPad"}"
// To print a stringified object with formatting,
// add "null" and "4" as parameters:
JSON.stringify(christmasList, null, 4);
// "{"lars": "Book","lisa": "sweater","lara": "iPad"}"
// JSON.parse Examples
// The following is a JSON string, so we cannot access the
// properties with dot notation (like christmasListStr.mike)
var christmasListStr = '{ "lars":"Book","lisa":"sweater","lara":"iPad" }'
// Let’s convert it to an object
var christmasListObj = JSON.parse (christmasListStr)
// Now that it is an object, we use dot notation
console.log(christmasListObj.lars) // Book