JavaScript Objects

https://www.dofactory.com/javascript/objects

avaScript Objects

Creating objects with object literals

A JavaScript object is a collection of properties where each property has a name and a value, 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 below we create an empty object, using object literal notation, and we are adding two properties after that:

var rect = {};          // creates an empty objectrect.width = 20;rect.height = 10;alert(rect.width);      // => 20alert(rect.height);     // => 10

Run

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

var rect = { width: 20, height: 10 };alert(rect.width);      // => 20alert(rect.height);     // => 10

Run

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

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

Run

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 objectrect.color = { red: 0, green: 255, blue: 128 }; // add new methodrect.getArea = function() {                        return this.width * this.height;};alert(rect.color.red);             // => 0alert(rect.color.green);           // => 255alert(rect.color.blue);            // => 128alert(rect.getArea());             // => 200

Run

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;    }};alert(rect.width);                 // => 20alert(rect.height);                // => 10alert(rect.color.red);             // => 0alert(rect.color.green);           // => 255alert(rect.color.blue);            // => 128alert(rect.getArea());             // => 200

Run Previous Next

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 };alert(rect.width);             // => 20 (dot notation)alert(rect["width"]);          // => 20 (bracket notation)

Run

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 notationalert(shape["bounding box width"]);   // => 20 for(var i = 1; i < 6; i++) {   var prop = "side" + i; // variable property name   alert(shape[prop]);    // => 5, 15, 25, 7, 12 }var property = "side1";alert(shape.property);    // => undefined  (dot notation does not work)

Run

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

Getting property names with for-in

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   alert(prop + ": " + car[prop]);  }

Run

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() {        alert(this.make + " " + this.model);    }};for (var prop in car) {   if (typeof car[prop] !== "function") {      alert(prop);         // => make, and model   }}

Run

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 };alert(circle.radius);             // => 8alert(delete circle.radius);      // => truealert(circle.radius);             // => undefined

Run

Creating objects with constructor functions

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:

var book = new Book("901-3865");alert(book.getIsbn());    // => Isbn is 901-3865

Run

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");alert(book.getIsbn());    // => Isbn is 901-3865

Run

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 JavaScript + jQuery Design Pattern Framework. 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   alert(t.message);                    // => Learning JSalert(window.message === undefined); // => truevar u = Task();                      // new is omitted!alert(u.message);                    // => error (not displayed in run)alert(window.message === undefined); // => falsealert(window.message);               // => Learning JS

Run

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 omittedalert(t.message);  // => Learning JS

Run

To learn more about avoiding common JavaScript errors, the JavaScript + jQuery Design Pattern Framework 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 objects a way to identify and examine themselves. Consider the example below:

function Circle(radius) {                        this.radius = radius;}Circle.prototype.getRadius = function() {    return this.radius;}var smallCircle = new Circle(5);alert(smallCircle.getRadius());    // => 5var largeCircle = new Circle(100);alert(largeCircle.getRadius());    // => 100

Run

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';alert(str);             // => hellothis.str = 'world';     // this refers to the global objectalert(str);             // => world

Run

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() {        alert(this === circle);        alert(this.radius);    }};circle.getRadius();                 // => true, 10var anotherCircle = {    radius: 12};anotherCircle.getRadius = circle.getRadius;anotherCircle.getRadius();         // => false, 12

Run

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() {            alert(this.name);        }    }}var result = student.detail.getName; result();                    // => First (global scope)student.detail.getName();    // => Last  (detail scope)  

Run

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'.

Prototypal 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 JavaScript + jQuery Design Pattern Framework 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.

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");alert(savings.getAccountHolders()[0]);      // => Jack Saveralert(savings.getAccountHolders()[1]);      // => Mary Saveralert(savings.getBank());                   // => Bank of Americasavings.bank = "JP Morgan Chase";alert(savings.getBank());                   // => JP Morgan Chase

Run

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 5var account = {    bank: "Bank of America",        // just the default value    getBank: function () {        return this.bank;    }};var savings = Object.create(account);alert(savings.bank);                // => Bank of America

Run

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 JavaScript + jQuery Design Pattern Framework 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

Navigation

Lionel

@Copyright 2023