JavaScript Tutorial for Programmers - Object (Dictionary)

I still remember the days of debugging CORS problem when I put together some projects using JavaScript (& ajax), “a very particular programming language” in my first impression. Recently I got a great opportunity. The new role uses JS, the browser-side script that is now winning in all sides, as the major language. So I tooke it as a good chance to learn JS more systematically, and this series will be part of the outcome of my study. As the name implies, I will not cover primary level such as “if, else” (condition), “for” (or any kinds of loops), or basic OOP concepts. Instead, I will focus only on differences so you can learn this versatile language like reviewing a pull request, and use it the next day in your next awesome project.

In JavaScript, it is hard to differentiate an object and a dictionary (a.k.a., map in some other languages):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var hero = {
name: 'iron man',
birth: 1971,
};
alert(hero["name"]);// use map key to fetch property
alert(hero.name);
var herodict = {
"name": 'iron man',
"birth": 1971,
};
alert(herodict["name"]);
alert(herodict.name);// use property name to fetch a value

Result:

1
2
3
4
iron man
iron man
iron man
iron man

According to the test result, they are the same, and it is officially called an object. Hense in the rest of text, I will use . when referring to properties to make it clear.

In the above example, the class of an object is defined in a one-off manner. To declare types that can be reusable: we use constructor and class (es6).

Constructor

A constructor is a special function used for creating an object:

Example:

1
2
3
4
5
6
7
8
9
function StarkIndustries(name, birth) {
this.name = name;
this.birth = birth;
}
var iron1 = new StarkIndustries('iron01', 2017);
var iron2 = new StarkIndustries('iron02', 2017);
alert(iron1.name);
alert(iron2.name);

Result:

1
2
iron01
iron02

By adding new before a function, we turn the function into a constructor that constructs an object.

Revisit this issue

Missing new falls into the this pitfall:

1
2
3
4
5
6
7
8
9
10
11
var name = "stark";
var birth = 1971;
function StarkIndustries(name, birth) {
this.name = name;
this.birth = birth;
}
var iron1 = StarkIndustries('iron01', 2017);
alert(iron1);
alert(name);
alert(birth);

Result:

1
2
3
undefined
iron01
2017

From the experiment above, we can observe that without new:

  1. this inside StarkIndustries() points to window, thus, the global variables(name ,birth) have been modified within the misused constructor;
  2. the misused StarkIndustries() returns a undefine.

So it is dangerous to call a function designed as a constructor without new. And a common practice is doing sanity check inside the constructor:

1
2
3
if (!(this instanceof StarkIndustries)) {
warn("StarkIndustries is a constructor and should be called with `new`");
}

Or you can use real constructor inside a real class.

Class

Example:

1
2
3
4
5
6
7
8
9
10
11
class Hero {
constructor(name, birth) {
this.name = name;
this.birth = birth;
}
}
var iron1 = new Hero('iron01', 2017);
var iron2 = new Hero('iron02', 2017);
alert(iron1.name);
alert(iron2.name);

Result:

1
2
iron01
iron02

What if new is missed here:

1
2
3
4
5
6
7
8
9
10
11
class Hero {
constructor(name, birth) {
this.name = name;// note, here we can still declare properties within constructor
this.birth = birth;
}
}
var iron1 = Hero('iron01', 2017);// error: Uncaught TypeError: Class constructor Hero cannot be invoked without 'new'
var iron2 = Hero('iron02', 2017);
alert(iron1.name);
alert(iron2.name);

The code triggers an error when we are about to create iron1. So class is safer than the pure constructor.

Dictionary

In the following example we examine more dictionary facets of an object. In particular, we will see how easily properties of an object can be added and removed like key-value entries.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function StarkIndustries(name, birth) {
this.name = name;
this.birth = birth;
}
var iron1 = new StarkIndustries('iron01', 2017);
alert(iron1);
alert(iron1.name);
alert(iron1.birth);
iron1.age = 0;
alert(iron1.age);
delete iron1.age;
alert(iron1.age);

Result:

1
2
3
4
iron01
2017
0
undefined

Besides the techniques described above, JavaScript provides prototype as a more flexible way to modify class definitions. prototype will be discussed in the next post.