We should repeat that objects are normally defined as instances of classes. This is what we showed you. In other object oriented languages when an object is instantiated a variable is created as a copy of the class. This means that for every existing object, think of 1000s in an array, a copy of all its methods take up space in computer memory. Not quite so in JavaScript. The common concepts such as properties, and methods however, do exist. But the methods are linked to the objects instead of copied to them.
We have already touched on objects related to the DOM. The DOM and the native objects of JavaScript are givens. We do not define them ourselves. The DOM is created by the browser as it renders the page. The JavaScript native objects are defined as part of the JavaScript language.
Array, Math, and Date
are some of the more commonly used native objects. Their
spec holds many methods that you might benefit from in
your daily coding with JavaScript. Please refer to them
for details. An excellent, the best, printed source
is [Fla11a].
Online you should probably use
https://developer.mozilla.org/en-US/docs/Web/JavaScript, or go directly to
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects
.
Generally MDN, Mozilla Developer Network is a treasure trove
of knowledge on all things web, especially, perhaps, JavaScript.
Now we have seen object creation and manipulation of individual objects. A bit on the sparse side, the examples had but one method in stead of several or many which is more normal. In this section we shall look at an example of creating objects and placing them in arrays for more "industrial" processing.
Die.js
/**
* Die object
*/
class Die {
constructor(i, t) {
this.snr = i; // serialno, index
this.type = t; // type, 2: coin, 6: die, ...
this.locked = false;
this.value = 0;
this.roll();
}
draw(where) {
let d = document.createElement("div");
d.setAttribute("class", "die");
d.setAttribute("id", "die" + this.snr);
if (this.locked) {
d.style.backgroundColor = "yellow";
}
let t = document.createTextNode(this.value);
d.appendChild(t);
d.addEventListener('click', lockFlipFlop);
$(where).appendChild(d);
}
roll() {
this.value = rollit(this.type);
}
lock() {
this.locked = true;
}
unlock() {
this.locked = false;
}
isLocked() {
return this.locked;
}
}
We see the Die defined, in the constructor,
with some properties
and methods. The properties will be given values on
instantiation thus
giving state to the object. The methods will be
linked to each object built on the Die
class.
The Die class is general, and may be used in
any application playing with dice. In one concrete case,
yatzy, it may be used as follows.
yatzyoo0.js
/*
* function to start game
* called on page load
*/
const start = function() {
dice = [];
tries = TRIES;
for (let i = 0; i < ANTAL; i++) {
let die = new Die(i, 6); // instantiates Die object
dice.push(die); // store it the array
die.draw("board"); // and paints it on the screen
}
$("rollem").addEventListener("click", function() {
if (tries > 0) {
rollDice();
redrawBoard("board");
tries -= 1;
} else {
score(); // must record score
// should prevent locking
// and prevent further score
// until after rollDice
tries = TRIES;
}
});
}
const ANTAL = 5; // number of dice
const TRIES = 3; // number of tries
var tries; // counter of tries, initialized in start
var dice; // dice array, initialized in start
window.addEventListener("load", start);
The constants ANTAL and TRIES
are defined in order to avoid spreading magic numbers
around the code. In addition two global variables are
defined. The array dice defined here to be
global will be initialized in the load
eventhandler start. The variable
tries control the number of rolls in each play.
The eventhandler start initializes the
variables as already mentioned. Then it, industrially,
creates a number of Die objects placing
each of them in the dice array. You will
look aside into the init method of
Die and see that the die is rolled as part of
initialization. The you put the die on the screen.
The bottom part of start creates an
eventlistener listening to the clicking of the
Roll button of the HTML5 page. The
eventhandler is built in as an immediate
function. The code of the eventhandler
does not execute when
start runs. It runs asynchronously whenever
the event triggers.
The handler rolls the dice by running a function. The dice are then painted onto the screen. This is done by clearing the dice and repainting them. These two functions are shown below.
yatzyoo0.js
/*
* Loop through the array of dice
* drawing each one on the screen
* with method defined in object
*/
const redrawBoard = function(foo) {
clrBoard(foo);
for (let die of dice) {
die.draw(foo);
}
}
/*
* Loop through the array of dice
* rolling each die not locked
* with method defined in object
*/
const rollDice = function() {
for (let die of dice) {
if(!die.isLocked()) {
die.roll();
}
}
}
You may have noticed
for (let die of dice) {
if(!die.isLocked()) {
die.roll();
}
}
this is new, ES6, and equivalent to
for (let i = 0; i < ++i) {
if(!dice[i].isLocked()) {
dice[i].roll();
}
}
The new variant is useful and clearer than the old, and may be used if you have no need for the index.
An OO conventional phenomenon inheritance means that the a subclass inherits, and adds to the behaviour of the superclass. Here we have constructed an illustrative example.
'use strict';
/**
* Person object
*/
export class Person {
constructor(name, age, weight, sex) {
this.name = name;
this.age = age;
this.weight = weight;
this.sex = sex;
}
getName() {
return this.name;
}
setName(name) {
this.name = name;
}
setWeight(w) {
this.weight = w;
}
toString() {
let s = 'I am a person: My name is: ' + this.getName();
if (this.sex !== 'F') {
s += ', age: ' + this.age;
s += ', weight: ' + this.weight;
}
return s;
}
}
'use strict';
/**
* Student object is a Person object plus something
*/
import {Person} from './nmlPersonC2.js';
export class Student extends Person {
constructor(name, age, weight, sex, program) {
super(name, age, weight, sex);
this.program = program;
}
getProgram() {
return this.program;
}
setProgram(prog) {
this.program = prog;
}
toString() {
let s = super.toString();
s += '. I am a ';
s += this.getProgram();
s += ' student.';
return s;
}
}
<!doctype html>
<html language="en">
<!-- nmlPersonOO1.html -->
<head>
<meta charset="utf-8"/>
<title>Objects, OLOO</title>
<script src="nmlPersonC2.js"></script>
<script src="nmlStudentC2.js"></script>
</head>
<body>
<h1>Inheritance Example</h1>
<p>
Create a Student object based on Person.
Add a couple of methods and demonstrate usage.
</p>
<p>
Please press Ctrl->Shift->I to read the console log.
<div>
<script type='module'>
import {Student} from './nmlStudentC2.js';
import {Person} from './nmlPersonC2.js';
let st1 = new Student('Adelaide', 32, 56, 'F', 'Webdev'); // give st1 state
st1.setName('Zelda'); // test setter
st1.setProgram('WebDev'); // test setter
console.log(st1.toString()); // print again
let st2 = new Student('Bruce', 22, 200, 'M', 'Webdev'); // give st2 state
st2.setProgram('WebDev'); // test setter
console.log(st2.toString()); // print again
let st3 = new Person('Bruce', 22, 200, 'M'); // give st3 state
console.log(st3.toString()); // print again
console.log(st3); // print again // no auto toString
</script>
</div>
</body>
</html>