Objects (Part2) properties and methods

June 29, 2017


Introduction

You’re already familiar with the concept of objects, but so far we’ve only seen one simple form, called “objects literals” or “singleton objects”. I think we’ve referred to them as “simple objects” in the course. Here is an example:

1
2
3
4
5
6
var js1 = {
    courseName: 'JavaScript intro',
    weeks: 5,
    madeBy: 'W3Cx',
    author: 'Michel Buffa' // no "," after the last property!, even if ES5/6 accept it
}

And we access properties values using the “.” operator, like this:

1
2
3
4
5
> js1.author
"Michel Buffa"

> js1.weeks
5

However, we haven’t explained 90% of what is going on, and what we can do with “objects”. Our objective in this module, is to explain the most important features of objects, while keeping it simple (more advanced topics will be taught in a future “JavaScript Advanced” course, such as prototypes, context binding, etc.).

Features you will learn:

  • The relationship between JavaScript objects and arrays,
  • What a "reference" is in a programming language,
  • How to embed methods in your objects (functions inside an object),
  • The "this" object that you very often encounter in Object Oriented JavaScript code,
  • How to add methods and properties to your objects,
  • How to make multiple objects of the same class using ES6 classes,
  • The built-in JavaScript objects and classes: Array, String, RegExp, Date, Math, Error, etc. And, we will remind you about objects such as navigator, document, window, screen, etc.

Features you will learn in an upcoming course:

  • JavaScript prototypes,
  • Inheritance,
  • Advanced manipulations of properties and methods,
  • Methods such as bind, call, etc., that can be useful for changing the value of "this",
  • And more!

From objects to arrays

In Javascript, an object = a table whose keys/indexes are defined!

Important note: Darth Vader is called “Dark Vador” in the French versions of SW, and, as a French tutor, I think it’s cool to give to one of the heroes an international name. :-)

Look at this array:

1
2
3
4
5
6
7
8
> var darkVador = ['villain', 'half human half machine'];
undefined

> darkVador[0]
"villain"

> darkVador[1]
"half human half machine"

And now, look at this object:

1
2
3
4
var darkVador = {
    job: 'villain',
    race: 'half human half machine'
};

They look a bit similar, don’t they?

  • Same name of the variable that contains the object = darkVador
  • Instead of '[' and ']' that we used for defining an array, we use '{' and '}' for defining an object
  • The elements of the object (its properties) are separated by a comma ','
  • The pairs of keys/values are separated by ':' as in race: 'half human, half machine'
  • The last pair of keys/values has no ',' at the end.

It is possible to access the object’s properties with “.” or with brackets

We saw that we can use the “.” operator, followed by the property name. It’s also possible to use the bracket notation, and manipulate the object as an array whose indexes, instead of being 0, 1, 2 etc., are the property names!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
> var book = {
title: 'Le Petit Prince',
author: 'Saint-Exupery'
};
undefined

> var title = book.title;
undefined

> title;
"Le Petit Prince"

> var title = book['title'];
undefined

> title
"Le Petit Prince";

> var author = book['author'];
undefined

> author;
"Saint-Exupery"

As you can see, if you look at lines 7-10 and 13-16, writing book.title or book[‘title’] is equivalent!

In JavaScript, objects are arrays whose indexes are property names: please remember this!


Property declaration syntax

Property names: different possibilities

We can put single or double quotes around the name of the property, or nothing at all:

1
2
3
var louis = {age: 40}; // WE DO THIS MOST OF THE TIME!
var louis = {"age": 40};
var louis = {'age': 40};

In some cases we have to put quotes around the property name:

  • When it is a reserved word from JavaScript,
  • Or it contains spaces or special characters,
  • Or it begins with a number.

Examples:

1
2
3
4
5
book.1stPublication = '6 avril 1943'; // begins with a number
                                      // Throws a SyntaxError
book['1stPublication'] = '6 avril 1943'; // OK
book.date of publication = '6 avril 1943'; // spaces not allowed!
book['date of publication'] = '6 avril 1943'; // allowed, but avoid!
Another classic case where the name of a property is in a variable

In this case it is necessary to use the syntax with ‘[’ and ‘]’ …

Example:

1
2
3
4
5
> var key = 'title';
undefined

> book[key];
"Le Petit Prince"

An object can contain another object

Example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
> var book = {
    name: 'Catch-22',
    published: 1961,
    author: {                 // embedded object!
        givenName: 'Joseph',
        familyName: 'Heller'
    }
};
undefined

> book.author.givenName;
"Joseph"

> book.author.familyName;
"Heller"

Accessing the embedded object author is done by chaining property accesses using the “.” operator, like in book.author.givenName (here we access the givenName property of the object author, which is also a property of the book object).


Elements, properties and methods

Some vocabulary:

  • For arrays, we speak of elements
  • For objects, we talk about properties
  • But a property can also be a function, in which case it is called a method

Yes, it is possible for an object’s property to be a function!

A very simple example:

1
2
3
4
5
6
var medor = {
    name: 'Benji',
    bark: function(){
        alert('Ouarf, Ouarf!');
    }
};

In this example, the bark property’s value is a function, so we call bark “a method”.

__A method is a special property that corresponds to the object’s behavior

Properties correspond to an object’s DNA (its characteristics), and are nouns (age, name, etc.)

Methods correspond to an object’s behavior and are verbs (bark, move, changeSpeed, etc.)

Calling a method

Since a method is a property we can use the ‘.’ operator (or brackets with the method’s name as a string index).

Let’s see some examples:

JavaScript source code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var darkVador = {
  race: 'human',
  job: 'villain',
  talk: function() {
    return 'come to the dark side, Luke!';
  },
  describeYourself: function() {
    return "I'm a " + this.race + " and I'm a " + this.job + " in a series of movies!";
  }
}

function dvSpeak() {
 let disp01 = document.querySelector('#disp01');    
 disp01.innerHTML += '<p>Dark Vador describes himself: ' + darkVador.describeYourself(); + '</p>';  document.body.innerHTML += '<p>Dark Vador says ' + darkVador.talk(); + '</p>';
}

In line 1, we created a simple object named darkVador, that has two properties (race and job) and a method (talk).

In the dvSpeak function, at line 10, we call darkVador’s talk method. The syntax is a mix between the one for accessing a property (with the ‘.’ operator), and the one for calling a function (with parentheses and ‘;’ at the end).

When we write darkVador.talk(), we are executing the talk method of the object darkVador, but in plain English, we’re just asking Dark Vador to talk. We invoke its behavior!

Another example with the player we saw briefly in Module 2

Here is the last version of the player object we saw in our small game:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
// useful to have them as global variables
var canvas, ctx, w, h;
var mousePos;

var player = {
  x:10,
  y:10,
  width:20,
  height:20,
  color:'red'
}

window.onload = function init() {
    // called AFTER the page has been loaded
    canvas = document.querySelector("#myCanvas");

    // often useful
    w = canvas.width;
    h = canvas.height;  

    // important, we will draw with this object
    ctx = canvas.getContext('2d');

    // add a mousemove event listener to the canvas
    canvas.addEventListener('mousemove', mouseMoved);

    // ready to go !
    mainLoop();
};

function mouseMoved(evt) {
    mousePos = getMousePos(canvas, evt);
}

function getMousePos(canvas, evt) {
    // necessary work in the canvas coordinate system
    var rect = canvas.getBoundingClientRect();
    return {
        x: evt.clientX - rect.left,
        y: evt.clientY - rect.top
    };
}

function movePlayerWithMouse() {
  if(mousePos !== undefined) {
    player.x = mousePos.x;
    player.y = mousePos.y;
  }
}

function mainLoop() {
  // 1 - clear the canvas
  ctx.clearRect(0, 0, w, h);

  // draw the player
  drawFilledRectangle(player);

  // make the player follow the mouse
  movePlayerWithMouse();

  // ask for a new animation frame
  requestAnimationFrame(mainLoop);
}

function drawFilledRectangle(r) {
    // GOOD practice: save the context, use 2D trasnformations
    ctx.save();

    // translate the coordinate system, draw relative to it
    ctx.translate(r.x, r.y);

    ctx.fillStyle = r.color;
    // (0, 0) is the top left corner of the monster.
    ctx.fillRect(0, 0, r.width, r.height);

    // GOOD practice: restore the context
    ctx.restore();
}

Now that we’ve seen that we can include methods into objects, here is a better, more readable and more encapsulated version of our player object:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var player = {
    x:10,
    y:10,
    width:20,
    height:20,
    color:'red',
    move(x, y) {
        // change x and y coordinates of the player
        // TODO!
    },
    draw() {
        // draw the player at its current position
        // with current width, height and color
        // TODO!
    }
}

Assuming that the move and draw methods are fully implemented, we will now be able to call:

  • player.move(mousePos.x, mousePos.y) to change the position of the player,
  • player.draw() to draw the player at its current position, with its current size and color.

Readability is better, it is like asking the player to move, or asking it to draw itself. And we do not need to pass the x, y, width, height, color to the draw method: it is inside the player object, and it can access all its internal property values!

In the next section we will look at how we can access other object’s properties from a method or call other methods.

The this keyword: Accessing properties from a method

The this keyword!

When one wants to access an object property or wants to call another method from an object method, we must use the this keyword. In the code of the player object, this means “from this object”.

Let’s look at our game again, with a new version of the player object - this time fully functional:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
var player = {
    x:10,
    y:10,
    width:20,
    height:20,
    color:'red',

    move: function(x, y) {
        this.x = x; // this.x is the property of "this object"
        this.y = y;
    },

    draw: function(ctx) {
        // draw the player at its current position
        // with current width, height and color
        // it's nearly the same code as the old drawFilledRect function
        ctx.save();

        // translate the coordinate system, draw relative to it
        ctx.translate(this.x, this.y);

        ctx.fillStyle = this.color;
        // (0, 0) is the top left corner of the monster
        ctx.fillRect(0, 0, this.width, this.height);

        // BEST practice: restore the context
        ctx.restore();
    }
}

Notice that we’ve used this followed by the ‘.’ operator every time we’ve had to access the current value of an object’s property (lines 9, 10, 20, 22 and 24).

We passed the canvas’ graphic context as a parameter to the draw method (it’s always good not to create dependencies when making objects). Passing the context as a parameter avoids using it as a global variable. If in another project we’ve got a context named “context” instead of “ctx”, then we will just change the parameter when we call player.draw, otherwise we would have had to rename all occurrences of ctx in the code).

Same with the mouse coordinates we passed to the move method.

Let’s see the Dark Vador example with the use of this in a method

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var darkVador2 = {
  race: 'human',
  job: 'villain',
  talk: function() {
    return 'come to the dark side, Luke!' + this.breathe();
  },
  describeYourself: function() {
    return "I'm a " + this.race + " and I'm a " + this.job + " in a series of movies!" + this.breathe();
  },
  breathe() {
    return ".....shhhhhhhhh.....";
  }
}

function dvSpeak2() {
 let disp02 = document.querySelector('#disp02');
 disp02.innerHTML += '<p>Dark Vador describes himself: ' + darkVador2.describeYourself(); + '</p>';  disp02.innerHTML += '<p>Dark Vador says: ' + darkVador2.talk(); + '</p>';
}

Properties and methods can be added/deleted after an object has been defined

Look at the JS code. This time we created an empty object and added properties and methods afterwards.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// empty object with no properties/methods
var darkVador3 = {};

// add properties after darkVador has been created
 darkVador3.race = 'human';
  darkVador3.job = 'villain';
  darkVador3.talk = function() {
    return 'come to the dark side, Luke!' + this.breathe();
  };

  darkVador3.describeYourself = function() {
    return "I'm a " + this.race + " and I'm a " + this.job + " in a series of movies!" + this.breathe();
  };

  darkVador3.breathe = function() {
    return ".....shhhhhhhhh.....";
  };

Deleting a property or a method

You can use the JavaScript keyword “delete” to delete an object’s property (it will become undefined).

Example:

Look at the JS code. This time we created an empty object and added properties and methods afterwards.

Click the button below (it will delete the “race” property of the darkVador object). Then click again the button above and see the “undefined” value of the darkVador.race property now.

1
2
3
4
function deleteSomeProperties() {
  delete darkVador.race;
  delete darkVador.job;
}