Dofactory.com
Dofactory.com
Earn income with your JavaScript skills
Sign up and we'll send you the best freelance opportunities straight to your inbox.
We're building the largest freelancing marketplace for people like you.
By adding your name & email you agree to our terms, privacy and cookie policies.

JavaScript Objects

A JavaScript Object is a standalone container that holds multiple properties with values and methods (functions). An example is a customer object with firstName, lastName, and email properties, and a sendMessage method.

JavaScript Tutorial

Object Literals

A JavaScript object is a collection of properties and methods similar to Hash, Map, or Dictionary in other languages. The name of a property can be any string, including an empty string. The value can be any value, such as a string, boolean, number, and null, but it cannot be undefined. The object's properties can be defined even after you start using the object. But first, let's look at how we create objects in JavaScript.

The easiest way is to create a new object is with object literal notation which is bracketed by a pair of curly braces: {}. Properties and their values can be added as you go. In the example b elow we create an empty object, using object literal notation, and we are adding two properties after that:

var rect = {};                // creates an empty object
rect.width = 20;
rect.height = 10;

console.log(rect.width);      // => 20
console.log(rect.height);     // => 10

As an alternative you can immediately assign properties and their values in the literal notation.

var rect = { width: 20, height: 10 };

console.log(rect.width);      // => 20
console.log(rect.height);     // => 10

JavaScript objects are mutable, meaning you can modify their values.

var rect = { width: 20, height: 10 };
rect.width = 30;              // => modify value 

console.log(rect.width);      // => 30
console.log(rect.height);     // => 10

Property values are not limited to primitive types, like number or string; you can also add properties that are other objects, including functions. When a function is added to an object it is called a method.

var rect = { width: 20, height: 10 };

// add new object
rect.color = { red: 0, green: 255, blue: 128 };

// add new method
rect.getArea = function () {
    return this.width * this.height;
};

console.log(rect.color.red);             // => 0
console.log(rect.color.green);           // => 255
console.log(rect.color.blue);            // => 128
console.log(rect.getArea());             // => 200

You can define objects and all their member properties and methods in a single statement as object literal. Below we create a rectangle with two numeric properties, one object property, and a method.

var rect = {
    width: 20,
    height: 10,
    color: { red: 0, green: 255, blue: 128 }, // object property
    getArea: function () {                     // method property 
        return this.width * this.height;
    }
};

console.log(rect.width);                 // => 20
console.log(rect.height);                // => 10
console.log(rect.color.red);             // => 0
console.log(rect.color.green);           // => 255
console.log(rect.color.blue);            // => 128
console.log(rect.getArea());             // => 200

Object Properties

In this section we look at accessing, retrieving, and deleting object properties.

Accessing properties

Property values can be retrieved in one of two ways; dot notation and bracket notation. Below are examples of each:

var rect = { width: 20, height: 10 };

console.log(rect.width);             // => 20 (dot notation)
console.log(rect["width"]);          // => 20 (bracket notation)

Dot notation is used more often because it is easier to read and more compact. So when would you use bracket notation? Square brackets allow you to use property names that are not valid identifiers and don't work with dot notation, for example when they have spaces in them or start with a number. Also, bracket notation allows you to use property names that are variables. Examples of both are below:

var shape = {
    "bounding box width": 20,
    "bounding box height": 10,
    side1: 5,
    side2: 15,
    side3: 25,
    side4: 7,
    side5: 12
};

// could not be done with dot notation
console.log(shape["bounding box width"]);   // => 20 

for (var i = 1; i < 6; i++) {
    var prop = "side" + i;        // variable property name
    console.log(shape[prop]);     // => 5, 15, 25, 7, 12 
}

var property = "side1";

console.log(shape.property);      // => undefined  (dot notation does not work)

The last two statements are included to demonstrate that dot notation does not work with the property being a variable.


Property Names

#

To get a list of property names from an object use the for-in loop.

var car = { make: "Toyota", model: "Camry" };

for (var prop in car) {
    // => make: Toyota, and model: Camry
    console.log(prop + ": " + car[prop]);
}

The for-in loop returns all members of the object, that is, all properties and methods. If you don't need certain members or data types, you can exclude these from enumeration using the typeof operator. In the example below we skip functions.

var car = {
    make: "Toyota",
    model: "Camry",
    print: function () {
        console.log(this.make + " " + this.model);
    }
};
for (var prop in car) {
    if (typeof car[prop] !== "function") {
        console.log(prop);         // => make, and model
    }
}

Be aware that the order in which the properties are returned by a for-in loop is not guaranteed. If order is important you will need to manage your own list of properties (probably as an internal array).


Deleting Properties

#

Use the delete operator to remove a property from an object, like so:

var circle = { radius: 8 };

console.log(circle.radius);             // => 8
console.log(delete circle.radius);      // => true
console.log(circle.radius);             // => undefined

Constructor Ffunctions

Object literal notation, such as var x = {}, is preferred if all you need is a single object and there is no need for multiple instances. However, if you need multiple instances, it is better to use a constructor function. Here is an example of a book constructor function.

function Book(isbn) {
    this.isbn = isbn;
    this.getIsbn = function () {
        return "Isbn is " + this.isbn;
    };
}

Properties, including methods, are assigned to the 'this' value in the function's body. In the above example a property and a function are assigned. Also notice that this function is capitalized (i.e. Book); constructor functions are capitalized by convention in JavaScript

To create a new object with this function you use the new operator followed by a function invocation. A function that is invoked this way is called a constructor function whose main purpose is to create and initialize a new object. Here we are creating a new book object:

function Book(isbn) {
    this.isbn = isbn;
    this.getIsbn = function () {
        return "Isbn is " + this.isbn;
    };
}

var book = new Book("901-3865");

console.log(book.getIsbn());    // => Isbn is 901-3865

When new Book() is invoked, JavaScript creates a new empty Object and sets an internal property which specifies that the new object's prototype is Book, that is, the newly created object inherits the prototype of the function. It then passes the Book() function two arguments: the new object as this (as a hidden parameter) and the "901-3865" as isbn. The function, in turn, sets the object's isbn property to "901-3865" and also adds the getIsbn() method to the object. JavaScript returns the newly created object to the caller which then assigns the new object to the book variable.

Each time you invoke new Book(), a new getIsbn method is created which is a rather inefficient because the method is the same for all book instances. A better approach is to let all instances share a single method which can be accomplished by adding getIsbn to the prototype of Book rather than the Book function itself. Here is how this is done:

function Book(isbn) {
    this.isbn = isbn;
}

Book.prototype.getIsbn = function () {
    return "Isbn is " + this.isbn;
};

var book = new Book("901-3865");

console.log(book.getIsbn());    // => Isbn is 901-3865

As you can see, it works the same as when getIsbn was not shared. This is a very common object creation pattern. To really get to know JavaScript, we present this pattern and many others in our unique Dofactory JS. Click here for more information.


Omitting new

#

If you forget to use the new keyword, your code will break without warning. There won't be any compile-time or runtime warnings. See the example below where we call the instructor function with new and later without new.

function Task() {
    this.message = "Learning JS";
}

var t = new Task();                        // includes new   

console.log(t.message);                    // => Learning JS
console.log(window.message === undefined); // => true

var u = Task();                            // new is omitted!

console.log(u.message);                    // => error (not displayed in runtime)
console.log(window.message === undefined); // => false
console.log(window.message);               // => Learning JS

Calling a constructor function without new is like calling an ordinary function. The this value in this call will not be bound to a new object. Instead, it is bound to the global object. Notice that the function is adding the message property to the global object (i.e. window). This is often referred to as polluting the global namespace.

You can protect yourself against this mistake by including a check at the beginning of each constructor function. Essentially, it checks if this is an instance of Task: if it is not, then it invokes new Task() returning a true new instance.

function Task() {
    if (!(this instanceof Task)) {
        return new Task();
    }
    this.message = "Learning JS";
}

var t = Task();          // new is omitted

console.log(t.message);  // => Learning JS

To learn more about avoiding common JavaScript errors, the Dofactory JS includes helpful guidelines about optimal object instantiation, object scopes, and object lifetimes through the use of design patterns and best practices. To learn more click here.


The value of this

In JavaScript, the this keyword provides an object a way to identify and examine itself. Consider the example below:

function Circle(radius) {
    this.radius = radius;
}

Circle.prototype.getRadius = function () {
    return this.radius;
}

var smallCircle = new Circle(5);
console.log(smallCircle.getRadius());    // => 5

var largeCircle = new Circle(100);
console.log(largeCircle.getRadius());    // => 100

We have two circles, a small one and a large one. Each knows the size of their radius because in the getRadius method this value refers to the object it called from.

However, this can refer to a different object as well; it all depends on the execution context. All JavaScript code runs in an execution context. You can imagine the execution context as the scope of a function. A call to a function creates a new execution context. Also, in recursive functions a new context is created each time a function makes a call to itself.

Code that is not inside a function executes in a global execution context in which this is bound to the global object. The example below shows that in the global context the str variable is the same as this.str.

var str = 'hello';
console.log(str);       // => hello

this.str = 'world';     // this refers to the global object
console.log(str);       // => world

The value of this inside a function body is determined how the function is invoked. The context is commonly furnished by the parent scope in which the function was invoked. Consider the example below:

var circle = {
    radius: 10,
    getRadius: function () {
        console.log(this === circle);
        console.log(this.radius);
    }
};

circle.getRadius();                 // => true, 10

var anotherCircle = {
    radius: 12
};

anotherCircle.getRadius = circle.getRadius;
anotherCircle.getRadius();         // => false, 12

When invoking circle.getRadius() JavaScript establishes an execution context for the function call and sets this to the circle object. anotherCircle does not have a getRadius() method, but can be copied from circle. Once copied and executed, the value of this refers to anotherCircle which is why the first alert, which tests for cicle, return false, because this is not of type circle.

There is an easy way to determine the value of 'this' in a function. Look at the immediate left side of the invocation parentheses () and determine the object to which it belongs to. Let's explain this with an example. Below we have three names with different scope. The First name has global scope and is a property of the global object, the Middle name is a student object property and the Last name is a detail object property.

var name = 'First';

var student = {
    name: 'Middle',
    detail: {
        name: 'Last',
        getName: function () {
            console.log(this.name);
        }
    }
}

var result = student.detail.getName;

result();                    // => First (global scope)
student.detail.getName();    // => Last  (detail scope)  

In the first example, the left side of the parentheses is the variable result which belongs to the global object when invoked. So we get its name which is 'First'.

The second example, the left side of the parentheses is getName, which belongs to the detail object, so we get its name which is 'Last'.


Inheritance

Unlike classical inheritance where classes inherit from classes, JavaScript objects inherit from other objects, called prototypes, in a prototypal inheritance system.

Each object in JavaScript has a prototype property that points to a prototype object. There is nothing special about prototype objects, they are regular objects. Objects inherit all properties and methods that are available on the prototype object. Prototype objects themselves have prototypes, which leads to a prototype chain. This process in which objects inherit properties from objects in a prototype chain is referred to as prototypal inheritance. This model is simpler, smaller, and with less redundancy than that of classical inheritance.

Prototypal inheritance works on the concept of differential inheritance in which each item in the prototype chain only augments the differences with its parent. In other words, properties on prototype objects do not change or override properties in the parent object.

Let's look at an example. First, we create an account object with a bank property and a getBank method. This object will serve as the prototype for other objects like savings, checking, etc.

var account = {
    bank: "Bank of America",    // default value
    getBank: function() {
        return this.bank;
    }
};

Setting prototypes to an object is done by setting an object's prototype attribute to a prototype object. We can make this process a bit simpler by using a helper function, so let's first create this function; we'll name it createObject. What follows may seem a bit convoluted, but once you understand prototypes in JavaScript things will clear up. Furthermore, our Dofactory JS does a wonderful job of explaining the details of prototypal inheritance which will help you in your journey to becoming a true JavaScript rockstar. To learn more about this framework click here. But now back to createObject.

createObject accepts a prototype object as an argument, named p and returns a new object (a function object really) whose prototype attribute is set to the passed in prototype object. The prototype attribute is how JavaScript is able to follow an object's prototype chain.

function createObject (p) {
    var F = function () {};    // Create a new and empty function
    F.prototype = p;
    return new F();
}

With this function in place, we now like to create a savings object that inherits the functionality of the account object. First, we call our createObject function and pass in the account. This returns a new object with account as its prototype. Next we add member properties and methods that are specific to savings accounts.

function createObject(p) {
    var F = function () { };    // Create a new and empty function
    F.prototype = p;
    return new F();
}

var account = {
    bank: "Bank of America",   // just the default value
    getBank: function () {
        return this.bank;
    }
};

var savings = createObject(account);
savings.accountHolders = [];

savings.getAccountHolders = function () {
    return this.accountHolders;
}

savings.accountHolders.push("Jack Saver");
savings.accountHolders.push("Mary Saver");

console.log(savings.getAccountHolders()[0]);      // => Jack Saver
console.log(savings.getAccountHolders()[1]);      // => Mary Saver
console.log(savings.getBank());                   // => Bank of America

savings.bank = "JP Morgan Chase";
console.log(savings.getBank());                   // => JP Morgan Chase

After creating the savings account, we add a couple of account holders to the object. Next we see which bank is associated with these savings accounts; as expected it is "Bank of America". In the second to last statement we change the bank to "JP Morgan Chase", which is confirmed with the alert message. This confirms that the prototypal inheritance chain works as expected.


Building Prototypal Hierarchies

#

You can inherit from savings and add new properties and methods to a new parent object, and do this again and again. Inheritance can go many levels deep, but in order to not overcomplicate things, it is generally best to limit this to 2 or 3 levels. Of course, JavaScript will just continue searching the prototype chain until it hits the last object, the global object, and if the property or methods is not found, JavaScript return undefined. Lengthy inheritance chains will negatively affect performance, which is another reason to avoid deep hierarchies.

Prototypal inheritance is a highly memory efficient. A prototype is just a single object and derived object instances hold only references to their prototype. All replicated instances share a single copy of the members defined in the prototype object.

If you are coding to the EcmaScript 5 specification, then you don't need to write the aforementioned createObject function yourself. EcmaScript 5 has a built-in Object.create() method, which allows the creation of derived objects just as we did with our own createObject. Here is the code:

// EcmaScript 5
var account = {
    bank: "Bank of America",        // just the default value
    getBank: function () {
        return this.bank;
    }
};

var savings = Object.create(account);

console.log(savings.bank);          // => Bank of America

If you are an experienced object-oriented developer you know that programming a class-based language is impossible without understanding class based inheritance. Similarly, writing professional JavaScript requires a solid grasp of prototypal inheritance to be able to move beyond the simple JavaScript snippets that were common just a few years ago.

Our unique Dofactory JS provides the necessary information on prototypes and how to use these in your own projects by applying proven design patterns and best practices. Click here for more details.

Once you are familiar with prototypal inheritance it is actually easier to work with than classical inheritance. Its syntax is more tidy and simple. To customize your objects, you can quickly modify properties and methods at runtime without requiring a large amount of infrastructure code.


Last updated on Sep 30, 2023

Earn income with your JavaScript skills
Sign up and we'll send you the best freelance opportunities straight to your inbox.
We're building the largest freelancing marketplace for people like you.
By adding your name & email you agree to our terms, privacy and cookie policies.
Guides