Objects

  1. Creating objects
    1. Literal syntax
  2. Non-existing properties, undefined
  3. Checking if a key exists
  4. Iterating over keys-values
    1. Order of iteration
  5. Object variables are references
  6. Properties and methods
    1. Calling methods
  7. The constructor function, “new”
    1. A simple example
    2. An example with the method
  8. Built-in Objects
    1. String, Number, Boolean
  9. Summary

Objects in JavaScript are kind of two-faced.

From one side, an object is an associative array (called hash in some languages). It stores key-value pairs.

From the other side, objects are used for object-oriented programming, and that’s a different story.

In this section we start from the first side and then go on to the second one.

Creating objects

An empty object (you may also read as empty associative array) is created with one of two syntaxes:

1. o = new Object()
2. o = { }  // the same

It stores any values by key which you can assign or delete using “dot notation”:

var obj = {}       // create empty object (associative array)

obj.name = 'John'  // add entry with key 'name' and value 'John'

*!*
// Now you have an associative array with single element
// key:'name', value: 'John'
*/!*

alert(obj.name) // get value by key 'name'

delete obj.name // delete value by key 'name'

*!*
// Now we have an empty object once again
*/!*

You can use square brackets instead of dot. The key is passed as a string:

var obj = {}

obj['name'] = 'John'

alert(obj['name'])

delete obj['name']

There’s a significant difference between dot and square brackets.

  • obj.prop returns the key named ‘prop’
  • obj[prop] returns the key named by value of prop:
    var prop = 'name'
    
    // returns same as obj['name'], which is same as obj.name
    alert(obj[prop])
    

Literal syntax

You can also set values of multiple properties when creating an object, using a curly-bracketed list: { key1: value1, key2: value2, ... }.

Here’s an example.

Literal syntax is a more readable alternative to multiple assignments:

var menuSetup = {
    width:  300,
    height: 200,
    title: "Menu"
}

// same as:

var menuSetup = {}
menuSetup.width = 300
menuSetup.height = 200
menuSetup.title = 'Menu'

  1. Create an empty object user.
  2. Add a property name with value John.
  3. Change value of name to Serge.
  4. Remove property name from the object.
Open solution
Solution

var user = { };

user.name = "John";

user.name = "Serge";

delete user.name;

It is also possible to create nested objects:

var user = {
  name:  "Rose",
  age: 25,
  size: {
    top: 90,
    middle: 60,
    bottom: 90
  }
}

alert( user.name ) // "Rose"
alert( user.size.top ) // 90

Getting an object dump in Firefox

For debugging purposes, it is possible to get an object dump by calling toSource method, supported only in Firefox.

var user = {
  name:  "Rose",
  size: {
    top: 90,
    middle: 60
  }
}

alert( user.toSource() ) // works only in Firefox

Non-existing properties, undefined

We can try to get any property from an object. There will be no error.

But if the property does not exist, then undefined is returned:

var obj = {}

var value = obj.nonexistant

alert(value)

So it’s easy to check whether a key exists in the object, just compare it against undefined:

if (obj.name !== undefined) { // strict(!) comparison 
  alert(" I've got a name! ")
}

Checking if a key exists

A peculiar coder (I bet you are) might have a question.

What if I assign a key to undefined explicitly? How to check if whether the object got such key?

var obj = { key: undefined }

alert( obj.key ) // undefined.. just if there were no key

Hopefully, there is a special "in" operator to check for keys. It’s syntax is "prop" in obj, like this:

var obj = { key: undefined }

alert("key" in obj) // true, key exists
alert("blabla" in obj) // false, no such key

In real life, usually null is used a “no-value”, leaving undefined for something… truly undefined.

Iterating over keys-values

There is a special for..in syntax to list object properties:

for(key in obj) { 
  ... obj[key] ...
}

The following example demonstrates it.

var menu = {
    width:  300,
    height: 200,
    title: "Menu"
};

for(var key in menu) {
    var val = menu[key];
    
    alert("Key: "+key+" value:"+val);
}

Note how it is possible to define a variable right inside for loop.

Order of iteration

In theory, the order of iteration over object properties is not guaranteed. In practice, there is a de-facto standard about it.

  • IE<9, Firefox, Safari always iterate in the order of definition.
  • Opera, IE9, Chrome iterate in the order of definition for string keys.
    Numeric keys become sorted and go before string keys.

Try the code below in different browsers.

var obj = {
  "name": "John",
  "1": 1,
  age: 25,
  "0": 0
}
obj[2] = 2 // add new numeric
obj.surname = 'Smith' // add new string

for(var key in obj) alert(key) 
// 0, 1, 2, name, age, surname  <-- in Opera, IE9, Chrome
// name, 1, age, 0, 2, surname  <-- in IE<9, Firefox, Safari

Here “numeric keys” are those which can be parsed as integers, so "1" is a numeric key.

There is an issue about it in Chrome, with long discussion at http://code.google.com/p/v8/issues/detail?id=164.

Force iteration order over numeric keys

Sometimes, we want for..in to keep the iteration order for numeric keys across all browsers.

For example, server may generate a JavaScript object with select options, something like:

var countries = {
  // every option is given as "id": "title"
  "5": "Afghanistan",
  "3": "Brunei",
  "8": "Italy"
}

And now we need to build SELECT with these options in same order. But Chrome won’t let us, it will resort numeric keys.

An ugly, but working hack is to prepend numeric keys by an underscore '_'. When browser reads such object, it removes the underscore:

var countries = {
  // _id: title
  "_5": "Afghanistan",
  "_3": "Brunei",
  "_8": "Italy"
}
for(var key in countries) {
  alert(key.substr(1)) // keeps the order always
}

Now all browsers keep the order.

Object variables are references

A variable which is assigned to object actually keeps reference to it. That is, a variable stores kind-of pointer to real data.

You can use the variable to change this data, this will affect all other references.

var user = { name: 'John' }; // user is reference to the object

var obj = user;  // obj references *!*same object*/!*

*!*obj*/!*.name = 'Peter'; // change data in the object

alert(*!*user*/!*.name);  // now Peter

Same happens when you pass an object to function. The variable is a reference, not a value.

Compare this:

function increment(val) {
  val++
}

val = 5
increment(val) 

alert(val) // val is still 5

And this (now changing val in object):

var obj = { val: 5}

function increment(obj) {
  obj.val++
}
increment(obj)

alert(obj.val) // obj.val is now 6

The difference is because in first example variable val is changed, while in second example obj is not changed, but data which it references is modified instead.

Create a function multiplyNumeric which gets an object and multiplies all numeric properties by 2. It should work like this:

// before call
var menu = {
    width: "200",  
    height: "300",
    title: "My menu"
}

multiplyNumeric(menu)

// after call
menu = {
    width: 400,
    height: 600,
    title: "My menu"
}

P.S. The function to check for numericality:

function isNumeric(n) { 
  return !isNaN(parseFloat(n)) && isFinite(n)
}

Open solution
Solution

The solution below uses !isNaN(x) to check for a number.

var menu = {
  width: 200,
  height: 300,
  title: "My menu"
}

function isNumeric(n) { 
  return !isNaN(parseFloat(n)) && isFinite(n)
}

function multiplyNumeric(obj) {
  for(var key in obj) {
    var val = obj[key]
    if (isNumeric(val)) {
      obj[key] = val*2
    }
  }
}

multiplyNumeric(menu)

alert("menu width="+menu.width+" height="+menu.height+" title="+menu.title)

Properties and methods

You can store anything in object. Not just simple values, but also functions.

var user = {
    name: "Guest",
    askName: function() {
        this.name = prompt("Your name?")
    },
    sayHi: function() {
        alert('Hi, my name is '+this.name)
    }
}

To check if a method is supported, we usually check it’s existance by if:

if (user.askName) user.askName()

Calling methods

When you put a function into an object, you can call it as method:

var user = {
    name: "Guest",
    askName: function() {
        this.name = prompt("Your name?")
    },
    sayHi: function() {
        alert('Hi, my name is '+this.name)
    }
}

user.askName()
user.sayHi()

Note the this keyword inside askName and sayHi. When a function is called from the object, this becomes a reference to this object.

Create an object named summator with two methods:

  • sum(a,b) returns a sum of two values
  • run() prompts the visitor for two values and outputs their sum.

As the result, summator.run() should prompt for two values and alert their sum.

You can see it here in action: tutorial/intro/object/summator2.html

Open solution
Solution

The solution: tutorial/intro/object/summator2.html

Create an object ladder with chainable calls.

The source:

var ladder = {
  step: 0,
  up: function() { 
    this.step++ 
  },
  down: function() { 
    this.step-- 
  },
  showStep: function() { 
    alert(this.step) 
  }
}

Currently it works in a dull way:

ladder.up()
ladder.up()
ladder.down()
ladder.showStep() // 1

Modify the code, so the methods can be chained like this:

ladder.up().up().down().up().down().showStep()  // 1

Open solution
Solution

The solution is to return this on every call:

var ladder = {
  step: 0,
  up: function() { 
    this.step++ 
    return this
  },
  down: function() { 
    this.step-- 
    return this
  },
  showStep: function() { 
    alert(this.step) 
    return this
  }
}

ladder.up().up().down().up().down().showStep()  // 1

The constructor function, “new”

An object can be created literally, using obj = { ... } syntax.

Another way of creating an object in JavaScript is to construct it by calling a function with new directive.

A simple example

function Animal(name) {
  this.name = name
  this.canWalk = true  
}

var animal = new Animal("beastie")

alert(animal.name)

A function takes the following steps:

  1. Create this = {}.
  2. The function then runs and may change this, add properties, methods etc.
  3. The resulting this is returned.

So, the function constructs an object by modifying this.

The result in the example above:

animal = {
  name: "beastie",
  canWalk: true
}

If the function returns an object, `this` is ignored

This feature is rarely used, but still interesting to know:

function Animal() {
  this.name = 'Mousie'
  return { name: 'Godzilla' }  // <-- will be returned
}

alert( new Animal().name )  // Godzilla

Traditionally, all functions which are meant to create objects with new have uppercased first letter in the name.

By the way, a call without arguments may omit braces:

var animal = new Animal()
// same as
var animal = new Animal

In both cases animal.name will be undefined.

An example with the method

Let’s declare a function User and create two objects with sayHi method.

function User(name) {
  this.name = name
 
  this.sayHi = function() {
    alert(" I am "  +this.name)
  };
}

var john = new User("John")
var peter = new User("Peter")

john.sayHi()
peter.sayHi()

Create an constructor function Summator which creates an object with two methods:

  • sum(a,b) returns a sum of two values
  • run() prompts the visitor for two values and outputs their sum.

new Summator().run() should prompt for two values and alert their sum.

You can see it here in action: tutorial/intro/object/summator2New.html

Open solution

Built-in Objects

The “standard” library of JavaScript includes a list of built-in objects.

For example:

  • Math provides methods for mathematical computations,
  • Date - for dates,
  • RegExp - for regular expressions.

Functions are also objects, instances of the new Function. We’ll meet their advanced usage further in the book.

String, Number, Boolean

The three objects are standing apart from the others. These are String, Number, Boolean.

Unlike other objects, they are never created explicitly. No one should ever make a new String. Primitives should be used instead.

The purpose of these objects is to support methods, which can be called directly on a primitive, like this:

alert( "string".length )
alert( "lala".toUpperCase() )

It works, because the interpreter converts a primitive to object, calls its method, and the returned value is primitive again.

Same with numbers:

alert( 123.456.toFixed(2) )

alert( 123..toFixed(2) ) // Two dots is not a typo. 
// 123.toFixed(2) won't work, because the expects the decimal part after '.'

Summary

  • Objects are associative arrays with additional features.
    • Assign keys with obj[key] = value or obj.name = value
    • Remove keys with delete obj.name
    • Iterate over keys with for(key in obj), remember iteration order for string keys is always in definition order, for numeric keys it may change.
  • Properties, which are functions, can be called as obj.method(). They can refer to the object as this.
  • Properties can be assigned and removed any time.
  • A function can create new objects when run in constructor mode as new Func(params).

    It takes this, which is initially an empty object, and assigns properties to it. The result is returned (unless the function has explicit return anotherObject call).

    Names of such functions are usually capitalized.

See also:

Tutorial

Donate

Donate to this project