From arrays to objects

Exclusive offer: get 50% off this eBook here
Object-Oriented JavaScript

Object-Oriented JavaScript — Save 50%

Create scalable, reusable high-quality JavaScript applications and libraries

$23.99    $12.00
by Kumar Chetan Sharma Stoyan Stefanov | July 2013 | Web Development

As we all know about JavaScript's primitive data types, arrays, and functions, it's time to make true to the promise of the book title and talk about objects.

In this article by Stoyan Stefanov and Kumar Chetan Sharma, authors of the book Object-Oriented JavaScript, you will learn how to create and use objects

(For more resources related to this topic, see here.)

An array is just a list of values. Each value has an index (a numeric key) that starts from zero and increments by one for each value.

> var myarr = ['red', 'blue', 'yellow', 'purple']; > myarr; ["red", "blue", "yellow", "purple"]. > myarr[0]; "red" > myarr[3]; "purple"

If you put the indexes in one column and the values in another, you'll end up with a table of key/value pairs shown as follows:

Key

Value

0

red

1

blue

2

yellow

3

purple

An object is similar to an array, but with the difference that you define the keys yourself. You're not limited to using only numeric indexes and you can use friendlier keys, such as first_name, age, and so on.

Let's take a look at a simple object and examine its parts:

var hero = { breed: 'Turtle', occupation: 'Ninja' };

You can see that:

  • The name of the variable that refers to the object is hero
  • Instead of [ and ], which you use to define an array, you use { and } for objects
  • You separate the elements (called properties) contained in the object with commas
  • The key/value pairs are divided by colons, as in key: value

The keys (names of the properties) can optionally be placed in quotation marks. For example, these are all the same:

var hero = {occupation: 1}; var hero = {"occupation": 1}; var hero = {'occupation': 1};

It's recommended that you don't quote the names of the properties (it's less typing), but there are cases when you must use quotes:

  • If the property name is one of the reserved words in JavaScript 
  • If it contains spaces or special characters (anything other than letters, numbers, and the _ and $ characters)
  • If it starts with a number

In other words, if the name you have chosen for a property is not a valid name for a variable in JavaScript, then you need to wrap it in quotes.

Have a look at this bizarre-looking object:

var o = { $omething: 1, 'yes or no': 'yes', '!@#$%^&*': true };

This is a valid object. The quotes are required for the second and the third properties, otherwise you'll get an error.

Later in this chapter, you'll see other ways to define objects and arrays in addition to [] and {}. But first, let's introduce this bit of terminology: defining an array with [] is called array literal notation, and defining an object using the curly braces {} is called object literal notation.

Elements, properties, methods, and members

When talking about arrays, you say that they contain elements. When talking about objects, you say that they contain properties. There isn't any significant difference in JavaScript; it's just the terminology that people are used to, likely from other programming languages.

A property of an object can point to a function, because functions are just data. Properties that point to functions are also called methods. In the following example, talk is a method:

var dog = { name: 'Benji', talk: function () { alert('Woof, woof!'); } };

As you have seen in the previous chapter, it's also possible to store functions as array elements and invoke them, but you'll not see much code like this in practice:

> var a = []; > a[0] = function (what) { alert(what); }; > a[0]('Boo!');

You can also see people using the word members to refer to properties of an object, most often when it doesn't matter if the property is a function or not.

Hashes and associative arrays

In some programming languages, there is a distinction between:

  • A regular array, also called an indexed or enumerated array (the keys are numbers)
  • An associative array, also called a hash or a dictionary (the keys are strings)

JavaScript uses arrays to represent indexed arrays and objects to represent associative arrays. If you want a hash in JavaScript, you use an object.

Accessing an object's properties

There are two ways to access a property of an object:

  • Using the square bracket notation, for example hero['occupation']
  • Using the dot notation, for example hero.occupation

The dot notation is easier to read and write, but it cannot always be used. The same rules apply as for quoting property names: if the name of the property is not a valid variable name, you cannot use the dot notation.

Let's take the hero object again:

var hero = { breed: 'Turtle', occupation: 'Ninja' };

Accessing a property with the dot notation:

> hero.breed; "Turtle"

Accessing a property with the bracket notation:

> hero['occupation']; "Ninja"

Accessing a non-existing property returns undefined:

> 'Hair color is ' + hero.hair_color; "Hair color is undefined"

Objects can contain any data, including other objects:

var book = { name: 'Catch-22', published: 1961, author: { firstname: 'Joseph', lastname: 'Heller' } };

To get to the firstname property of the object contained in the author property of the book object, you use:

> book.author.firstname; "Joseph"

Using the square brackets notation:

> book['author']['lastname']; "Heller"

It works even if you mix both:

> book.author['lastname']; "Heller" > book['author'].lastname; "Heller"

Another case where you need square brackets is when the name of the property you need to access is not known beforehand. During runtime, it's dynamically stored in a variable:

> var key = 'firstname'; > book.author[key]; "Joseph"

Calling an object's methods

You know a method is just a property that happens to be a function, so you access methods the same way as you would access properties: using the dot notation or using square brackets. Calling (invoking) a method is the same as calling any other function: you just add parentheses after the method name, which effectively says "Execute!".

> var hero = { breed: 'Turtle', occupation: 'Ninja', say: function () { return 'I am ' + hero.occupation; } }; > hero.say(); "I am Ninja"

If there are any parameters that you want to pass to a method, you proceed as with normal functions:

> hero.say('a', 'b', 'c');

Because you can use the array-like square brackets to access a property, this means you can also use brackets to access and invoke methods:

> hero['say']();

This is not a common practice unless the method name is not known at the time of writing code, but is instead defined at runtime:

var method = 'say'; hero[method]();

Best practice tip: no quotes (unless you have to)

Use the dot notation to access methods and properties and don't quote properties in your object literals.

Altering properties/methods

JavaScript allows you to alter the properties and methods of existing objects at any time. This includes adding new properties or deleting them. You can start with a "blank" object and add properties later. Let's see how you can go about doing this.

An object without properties is shown as follows:

> var hero = {};

A "blank" object

In this section, you started with a "blank" object, var hero = {};. Blank is in quotes because this object is not really empty and useless. Although at this stage it has no properties of its own, it has already inherited some. You'll learn more about own versus inherited properties later. So, an object in ES3 is never really "blank" or "empty". In ES5 though, there is a way to create a completely blank object that doesn't inherit anything, but let's not get ahead too much.

Accessing a non-existing property is shown as follows:

> typeof hero.breed; "undefined"

Adding two properties and a method:

> hero.breed = 'turtle'; > hero.name = 'Leonardo'; > hero.sayName = function () { return hero.name; };

Calling the method:

> hero.sayName(); "Leonardo"

Deleting a property:

> delete hero.name; true

Calling the method again will no longer find the deleted name property:

> hero.sayName(); "undefined"

Malleable objects

You can always change any object at any time, such as adding and removing properties and changing their values. But, there are exceptions to this rule. A few properties of some built-in objects are not changeable (for example, Math.PI, as you'll see later).

Using the this value

In the previous example, the sayName() method used hero.name to access the name property of the hero object. When you're inside a method though, there is another way to access the object the method belongs to: by using the special value this.

> var hero = { name: 'Rafaelo', sayName: function () { return this.name; } }; > hero.sayName(); "Rafaelo"

So, when you say this, you're actually saying "this object" or "the current object".

Constructor functions

There is another way to create objects: by using constructor functions. Let's see an example:

function Hero() { this.occupation = 'Ninja'; }

In order to create an object using this function, you use the new operator, like this:

> var hero = new Hero(); > hero.occupation; "Ninja"

A benefit of using constructor functions is that they accept parameters, which can be used when creating new objects. Let's modify the constructor to accept one parameter and assign it to the name property:

function Hero(name) { this.name = name; this.occupation = 'Ninja'; this.whoAreYou = function () { return "I'm " + this.name + " and I'm a " + this.occupation; }; }

Now you can create different objects using the same constructor:

> var h1 = new Hero('Michelangelo'); > var h2 = new Hero('Donatello'); > h1.whoAreYou(); "I'm Michelangelo and I'm a Ninja" > h2.whoAreYou(); "I'm Donatello and I'm a Ninja"

Best practice

By convention, you should capitalize the first letter of your constructor functions so that you have a visual clue that this is not intended to be called as a regular function.

If you call a function that is designed to be a constructor but you omit the new operator, this is not an error, but it doesn't give you the expected result.

> var h = Hero('Leonardo'); > typeof h; "undefined"

What happened here? There is no new operator, so a new object was not created. The function was called like any other function, so h contains the value that the function returns. The function does not return anything (there's no return), so it actually returns undefined , which gets assigned to h.

In this case, what does this refer to? It refers to the global object.

The global object

You have already learned a bit about global variables (and how you should avoid them). You also know that JavaScript programs run inside a host environment (the browser for example). Now that you know about objects, it's time for the whole truth: the host environment provides a global object and all global variables are accessible as properties of the global object.

If your host environment is the web browser, the global object is called window. Another way to access the global object (and this is also true in most other environments) is to use this outside a constructor function, for example in the global program code outside any function.

As an illustration, you can declare a global variable outside any function, such as:

> var a = 1;

Then, you can access this global variable in various ways:

  • As a variable a
  • As a property of the global object, for example window['a'] or window.a
  • As a property of the global object referred to as this:

    > var a = 1; > window.a; 1 > this.a; 1

Let's go back to the case where you define a constructor function and call it without the new operator. In such cases, this refers to the global object and all the properties set to this become properties of window.

Declaring a constructor function and calling it without new returns "undefined" :

> function Hero(name) { this.name = name; } > var h = Hero('Leonardo'); > typeof h; "undefined" > typeof h.name; TypeError: Cannot read property 'name' of undefined

Because you had this inside Hero, a global variable (a property of the global object) called name was created:

> name; "Leonardo" > window.name; "Leonardo"

If you call the same constructor function using new, then a new object is returned and this refers to it:

> var h2 = new Hero('Michelangelo'); > typeof h2; "object" > h2.name; "Michelangelo"

The built-in global functions can also be invoked as methods of the window object. So, the following two calls have the same result:

> parseInt('101 dalmatians'); 101 > window.parseInt('101 dalmatians'); 101

And, when outside a function called as a constructor (with new), also:

> this.parseInt('101 dalmatians'); 101

Object-Oriented JavaScript Create scalable, reusable high-quality JavaScript applications and libraries
Published: July 2008
eBook Price: $23.99
Book Price: $39.99
See more
Select your format and quantity:

The constructor property

When an object is created, a special property is assigned to it behind the scenes—the constructor property. It contains a reference to the constructor function used to create this object.

Continuing from the previous example:

> h2.constructor; function Hero(name) { this.name = name; }

Because the constructor property contains a reference to a function, you might as well call this function to produce a new object. The following code is like saying, "I don't care how object h2 was created, but I want another one just like it":

> var h3 = new h2.constructor('Rafaello'); > h3.name; "Rafaello"

If an object was created using the object literal notation, its constructor is the built-in Object() constructor function (there is more about this later in this chapter):

> var o = {}; > o.constructor; function Object() { [native code] } > typeof o.constructor; "function"

The instanceof operator

With the instanceof operator, you can test if an object was created with a specific constructor function:

> function Hero() {} > var h = new Hero(); > var o = {}; > h instanceof Hero; true > h instanceof Object; true > o instanceof Object; true

Note that you don't put parentheses after the function name (you don't use h instanceof Hero()). This is because you're not invoking this function, but just referring to it by name, as with any other variable.

Functions that return objects

In addition to using constructor functions and the new operator to create objects, you can also use a normal function to create objects without new. You can have a function that does a bit of preparatory work and has an object as a return value.

For example, here's a simple factory() function that produces objects:

function factory(name) { return { name: name }; }

Using the factory() function:

> var o = factory('one'); > o.name; "one" > o.constructor; function Object() { [native code] }

In fact, you can also use constructor functions and return objects different from this. This means you can modify the default behavior of the constructor function. Let's see how.

Here's the normal constructor scenario:

> function C() { this.a = 1; } > var c = new C(); > c.a; 1

But now look at this scenario:

> function C2() { this.a = 1; return {b: 2}; } > var c2 = new C2(); > typeof c2.a; "undefined" > c2.b; 2

What happened here? Instead of returning the object this, which contains the property a, the constructor returned another object that contains the property b. This is possible only if the return value is an object. Otherwise, if you try to return anything that is not an object, the constructor will proceed with its usual behavior and return this.

If you think about how objects are created inside constructor functions, you can imagine that a variable called this is defined at the top of the function and then returned at the end. It's as if something like this happens:

function C() { // var this = {}; // pseudo code, you can't do this this.a = 1; // return this; }

Passing objects

When you assign an object to a different variable or pass it to a function, you only pass a reference to that object. Consequently, if you make a change to the reference, you're actually modifying the original object.

Here's an example of how you can assign an object to another variable and then make a change to the copy. As a result, the original object is also changed:

> var original = {howmany: 1}; > var mycopy = original; > mycopy.howmany; 1 > mycopy.howmany = 100; 100 > original.howmany; 100

The same thing applies when passing objects to functions:

> var original = {howmany: 100}; > var nullify = function (o) { o.howmany = 0; }; > nullify(original); > original.howmany; 0

Comparing objects

When you compare objects, you'll get true only if you compare two references to the same object. Comparing two distinct objects that happen to have the exact same methods and properties returns false.

Let's create two objects that look the same:

> var fido = {breed: 'dog'}; > var benji = {breed: 'dog'};

Comparing them returns false:

> benji === fido; false > benji == fido; false

You can create a new variable, mydog, and assign one of the objects to it. This way, mydog actually points to the same object:

> var mydog = benji;

In this case, benji is mydog because they are the same object (changing the mydog variable's properties will change the benji variable's properties). The comparison returns true :

> mydog === benji; true

And, because fido is a different object, it does not compare to mydog:

> mydog === fido; false

Objects in the WebKit console

Before diving into the built-in objects in JavaScript, let's quickly say a few words about working with objects in the WebKit console.

After playing around with the examples in this chapter, you might have already noticed how objects are displayed in the console. If you create an object and type its name, you'll get an arrow pointing to the word Object .

The object is clickable and expands to show you a list of all of the properties of the object. If a property is also an object, there is an arrow next to it too, so you can expand this as well. This is handy as it gives you an insight into exactly what this object contains.

You can ignore __proto__ for now; there's more about it in the next chapter.

console.log

The console also offers you an object called console and a few methods, such as console.log() and console.error(), which you can use to display any value you want in the console.

console.log() is convenient when you want to quickly test something, as well as in your real scripts when you want to dump some intermediate debugging information. Here's how you can experiment with loops for example:

> for (var i = 0; i < 5; i++) { console.log(i); } 0 1 2 3 4

Summary

This article talks about objects, how to work with properties and methods, and the various ways to create your objects.

Resources for Article :


Further resources on this subject:


About the Author :


Kumar Chetan Sharma

Kumar Chetan Sharma studied to be an electronics engineer and has always wanted to build an ultimate sound system. He then, by chance, got a part time job as a trainee HTML guy. From there he picked up CSS and JavaScript and there was no looking back. It was the time when JavaScript was used to validate forms or create fancy DHTML effects and IE6 was the only browser the world knew. He has been developing web applications since then, using LAMP stack. He has worked on white label social networking applications to web control panels for telecom and networked electrical charger infrastructures. He currently works as a frontend engineer for Yahoo! Search.

Stoyan Stefanov

Stoyan Stefanov is a Facebook engineer, author, and speaker. He talks regularly about web development topics at conferences and his blog www.phpied.com, and also runs a number of other sites, including JSPatterns.com—a site dedicated to exploring JavaScript patterns. Previously at Yahoo!, Stoyan was the architect of YSlow 2.0 and creator of the image optimization tool Smush.it.

A "citizen of the world", Stoyan was born and raised in Bulgaria, but is also a Canadian citizen, currently residing in Los Angeles, California. In his offline moments, he enjoys playing the guitar, taking flying lessons, and spending time at the Santa Monica beaches with his family.

Books From Packt


 iPhone JavaScript Cookbook
iPhone JavaScript Cookbook

JavaScript Testing Beginner's Guide
JavaScript Testing Beginner's Guide

Ext JS 4 First Look
Ext JS 4 First Look

 JavaScript Unit Testing
JavaScript Unit Testing

 Instant Meteor JavaScript Framework Starter [Instant]
Instant Meteor JavaScript Framework Starter [Instant]

 Learning JavaScriptMVC
Learning JavaScriptMVC

 jQuery UI 1.8: The User Interface Library for jQuery
jQuery UI 1.8: The User Interface Library for jQuery

 Learning jQuery, Third Edition
Learning jQuery, Third Edition


Your rating: None Average: 2 (4 votes)

Post new comment

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
W
5
m
W
a
Y
Enter the code without spaces and pay attention to upper/lower case.
Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software