- Creating objects
- Non-existing properties,
undefined
- Checking if a key exists
- Iterating over keys-values
- Object variables are references
- Properties and methods
- The constructor function, “new”
- Built-in Objects
- 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'
- Create an empty object
user
. - Add a property
name
with valueJohn
. - Change value of
name
toSerge
. - Remove property
name
from the object.
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
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.
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) }
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 valuesrun()
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
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
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:
- Create
this = {}
. - The function then runs and may change
this
, add properties, methods etc. - 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 }
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 valuesrun()
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
The solution: tutorial/intro/object/summator2New.html
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
orobj.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.
- Assign keys with
- Properties, which are functions, can be called as
obj.method()
. They can refer to the object asthis
. - 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 explicitreturn anotherObject
call).Names of such functions are usually capitalized.