October 7

Today we reviewed Objects (prototype constructors, instances) and began looking at arrays of objects. 


Objects: Categories (Classes) and Individuals (Instances)

When we define an Object, we’re usually talking about one of two different things:

  1. The abstracted definition of a category, or
  2. The specific qualities of an individual instance

When we talk about the definition of an abstract category, we consider the properties that all things in that category have, but which vary across individuals. For example:

  • Every CAR has properties such as: its make, model, year of manufacture, color, length, mileage, top speed, and license plate number. Every car also has properties like: stick or automatic, 2-door or 4-door, convertible or not, etc. Taken together, these (and other) properties help define what a CAR is.
  • Every HOUSE has properties such as: its number of floors, number of windows, number of doors, number of bedrooms, number of bathrooms; and its address, square footage, sale price, and year that it was built. Taken together, these (and other) properties help define what a HOUSE is.
  • Every PERSON has properties like their: name, sex, age, height, weight, hair color, eye color, and whether or not they wear glasses. Taken together, these (and other) properties help define what a PERSON is.

Each of the above is a description of a category or prototype, in the form of a list of properties that all instances of that category will have. By contrast, when we talk about individual instances, we consider the specific values assigned to those properties. Those values will vary from instance to instance.

  • My ride, which my family and I have nicknamed Yoshi, is a 2014 Toyota Prius. It’s gray, has 4 doors, gets 40 MPG, and has an automatic transmission. It is an instance of a CAR.
  • My home, which my family and I call the Basket of Cheer, has 2 floors, 3 bedrooms, 1 bathroom, 3 doors, and was built in 1953. It has an address in Oakland and it is an instance of a HOUSE.
  • I am named Golan; I’m male, 43 years old, 165 centimeters tall, with gray hair, and I do wear glasses. I am an instance of a PERSON.

Objects: Literals, Definitions and Constructors

The following examples are adapted from here.

The easiest way to create a JavaScript Object is with an object literal, wherein you simultaneously define and create an object in one statement. An object literal is a list of name:value pairs (like age:50) inside curly braces {}. The following example creates a new JavaScript object with four properties:

var myFather = {firstName:"John", lastName:"Doe", age:50, eyeColor:"blue"};

In these examples, pay very careful attention to semicolons, colons, dots, and commas. On the other hand, spaces and line breaks are not important. An object definition can span multiple lines:

var myFather = {
    firstName:"John",
    lastName:"Doe",
    age:50,
    eyeColor:"blue"
};

Just FYI: you might see other syntaxes used for creating objects; for example:

var myFather = new Object();
// Or alternatively, you might even see: 
// var myFather = {};
 
myFather.firstName = "John";
myFather.lastName = "Doe";
myFather.age = 50;
myFather.eyeColor = "blue";

Often, we wish to have an category definition that can be used to create many objects of the same type. The standard way to create an instance of a category is to use an object constructor function:

// This function is called an object "constructor". 
// It's a special type of function that you can call 
// with the information you want to store in your object, 
// and it makes ("constructs") the object for you:
 
function Person (first, last, age, eye) {
    this.firstName = first;
    this.lastName = last;
    this.age = age;
    this.eyeColor = eye;
}
 
// Below is what it looks like to call an object constructor. 
// Object constructors are useful when you want to declare 
// a bunch of objects: once you have the constructor, 
// you can make new objects with just one line.
// Calling a constructor makes "instances":
 
var myFather = new Person("John", "Doe", 50, "blue");
var myMother = new Person("Sally", "Rally", 48, "green");

Note how the constructor function above can be thought of as returning an Object of type Person.


About the Dot Operator

When you see the dot (“.”) operator, you will see it used in one of two ways:

  • To access an Object’s property
  • To invoke an Object’s method

Let’s elaborate on this by considering the official p5.js Examples discussed below.

Properties.
Every instance of the JitterBug class has a diameter, among other properties. You can assign new values to its diameter with the dot operator, and you can ask a given JitterBug what its diameter is with the dot operator:

var myBug = new JitterBug(); 
 
// assign myBug's diameter to be 50. 
myBug.diameter = 50; 
 
// retrieve myBug's diameter, assign variable D to have this value. 
var D = myBug.diameter;

When you’re accessing or assigning a property of an Object, the dot operator is like an apostrophe-S (‘s). If you see myBug.diameter, think “myBug’s diameter”.

Methods.
Every instance of the JitterBug class is able to move(). Another way of saying this, is that the JitterBug object provides a move() function (or method). You can ask a given bug to move().

var myBug = new JitterBug(); 
 
// Ask myBug to move itself 
myBug.move();

When you’re executing a function (or invoking a method) that belongs to a given Object, the dot operator is like a form of address; it means, “Hey you! Do this:”. If you see myBug.move(), think: “Hey myBug! I want you to move()!”.

As with any function, an Object’s methods may sometimes require arguments, and may sometimes return values.


Official p5.js Examples

Lauren McCarthy, creator of p5.js made this set of examples to introduce Objects.

Here is an introduction to Objects:

sketch

var bug;  // Declare object

function setup() {
  createCanvas(800, 200);
  // Create object
  bug = new JitterBug();
}

function draw() {
  background(50, 89, 100);
  bug.move();
  bug.display();
}

// Jitter class
function JitterBug() {
  this.x = random(width);
  this.y = random(height);
  this.diameter = random(10, 30);
  this.speed = 1;

  this.move = function() {
    this.x += random(-this.speed, this.speed);
    this.y += random(-this.speed, this.speed);
  };

  this.display = function() {
    ellipse(this.x, this.y, this.diameter, this.diameter);
  }
};

Now we introduce some more objects of the same type, in the example Multiple Objects:

sketch

var bug1;  // Declare objects
var bug2;
var bug3;
var bug4;

function setup() {
  createCanvas(800, 200);
  // Create object
  bug1 = new JitterBug();
  bug2 = new JitterBug();
  bug3 = new JitterBug();
  bug4 = new JitterBug();
}

function draw() {
  background(50, 89, 100);
  bug1.move();
  bug1.display();
  bug2.move();
  bug2.display();
  bug3.move();
  bug3.display();
  bug4.move();
  bug4.display();
}

// Jitter class
function JitterBug() {
  this.x = random(width);
  this.y = random(height);
  this.diameter = random(10, 30);
  this.speed = 1;

  this.move = function() {
    this.x += random(-this.speed, this.speed);
    this.y += random(-this.speed, this.speed);
  };

  this.display = function() {
    ellipse(this.x, this.y, this.diameter, this.diameter);
  };
}

If you’re doing something more than twice, you’re probably doing it the wrong way. Here we make an Array of Objects:

sketch

var bugs = []; // array of JitterBug objects

function setup() {
  createCanvas(800, 200);
  // Create objects
  for (var i=0; i<50; i++) {
    bugs.push(new JitterBug());
    // could also be written: bugs[i] = new JitterBug();
  }
}

function draw() {
  background(50, 89, 100);
  for (var i=0; i<bugs.length; i++) {
    bugs[i].move();
    bugs[i].display();
  }
}

// Jitter class
function JitterBug() {
  this.x = random(width);
  this.y = random(height);
  this.diameter = random(10, 30);
  this.speed = 1;

  this.move = function() {
    this.x += random(-this.speed, this.speed);
    this.y += random(-this.speed, this.speed);
  };

  this.display = function() {
    ellipse(this.x, this.y, this.diameter, this.diameter);
  };
}


Michelle’s Example

Our TA Michell3 Ma made the following example:

 
/*
 * Michelle Ma
 * michell3
 * Section E
 *
 * Example code with objects
 */
 
// Here are two ways to create an object
var human1 = { firstName: "Joe", age: 18 }
var human2 = new Object();
human2.firstName = "Riley";
human2.age = 20;
 
// Here is an array that will hold all my objects
var humans = [human1, human2];
 
function setup() {
    createCanvas(600, 600);
    noLoop();
 
    // This is a for loop that quickly makes
    // a bunch of humans and adds the new human
    // to the humans array
    var numHumans = 100;
    for (var i=0; i<numhumans ; i++) {
        var newHuman = new Object();
        newHuman.firstName = "human" + i.toString();
        newHuman.age = Math.round(random(1, 100));
        humans.push(newHuman);
    }
}
 
function draw() {
    // This is a for loop that prints the names
    // of all the humans in the humans array
    // It also finds the age of the oldest human
    var oldest = 0;
    for (var i=0; i<humans.length; i++) {
        // Is the current value of oldest younger than the
        // current human? If so, update the variable
        if (oldest < humans[i].age) {
            oldest = humans[i].age;
        }
        print(humans[i].firstName);
    }
    print(oldest);
}
 
// Function that changes the age of all the humans
function changeAge() {
    for (var i=0; i<humans.length; i++) {
        humans[i].age = Math.round(random(1, 100));
    }
}

A separate matter: finding the max of an array

Our TA Luca Damasco made this example to illustrate a good and bad way of searching through an array for the maximum value.

/* Luca Damasco
 * Section A 
 * ldamasco@andrew.cmu.edu
 * The Max Example
 */
 
/* This example is meant to illustrate that as with most concepts in
 * programming, we can find the largest element in an array in many ways.
 * Some happen to be MUCH better than others... Take note of this when you 
 * develop solutions to your assignments and projects! 
 */
 
var myArr = [];
 
//-----------------------------------
function setup() {
  nElems = 100; 
  for (var i = 0; i < nElems; i++) {
  	myArr.push(random(0,nElems));
  }
  beforeMax1 = millis();
  print(findMaxValueInArray1(myArr));
  print("Total Time for 'Max1' = " + (millis()-beforeMax1) + " milliseconds");
 
  beforeMax2 = millis();
  print(findMaxValueInArray2(myArr));
  print("Total Time for 'Max2' = " + (millis()-beforeMax2) + " milliseconds");
}
 
//-----------------------------------
/* We do (arr.length * arr.length) ("n-squared") checks! */ 
function findMaxValueInArray1(arr) {
  var biggest = -999999;
  var count = 0; 
  var largerFound = false; 
 
  for (var i = 0; i < arr.length; i++) {
    myElem = arr[i];
    for (var j = 0; j < arr.length; j++) {
    	count ++;
        if (myElem < arr[j]) {
          largerFound = true;
        } 
    }
 
    if (!(largerFound)) {
    	biggest = myElem;
    }
    largerFound = false;
  }
 
  print("Max1 count = " + count);
  return biggest;
}
 
 
//-----------------------------------
/* We only do arr.length checks! */  
function findMaxValueInArray2(arr) {
  var amax = -1;
  var count = 0; 
 
  for (var i = 0; i < arr.length; i++) {
  	count ++; 
    if (amax < arr[i]) {
      amax = arr[i];
    }
  }
 
  print("Max2 Count = " +  count); 
  return amax;
}