Object Literals

Objects in JavaScript are simplest when they are written as object literals.

let lotteryTicket = {
  customerName: "Bob Cratchit",
  datePurchased: "01/01/1993",
  jackpot: 3000000
}

You can also use a function constructor to create them. It looks like this. (Notice the capital letter and lower case letter.)

function LotteryTicket(customerName, datePurchased, jackpot) {
  this.customerName = customerName;
  this.datePurchased = datePurchased;
  this.jackpot = jackpot;
}

let lotteryTicket = new LotteryTicket("Bob Cratchit", "01/01/1993", 3000000)

These two ways of making the lotteryTicket are both fine. The first makes the object in a single step. The second takes two steps, but is more formal. Are there any other differences?

Object Constructors

Object Constructors are a formal way to define a type of object. If you make a lot of objects of the same type, you can use a constructor to make sure everything is uniform.

Making many lottery tickets might be more convenient with a constructor.

For example, many object literals can be verbose and prone to typos:

let scroogeTicket = {
  customerName: "Ebenezer Scrooge",
  datePurchased: "01/05/1993",
  jackpot: 8000000
}

let timTicket = {
  customerName: "Tiny Tim",
  datePurchased: "01/01/1993",
  jackpot: 3000000
}

let bobTicket = {
  customerName: "Bob Cratchit",
  datePurchased: "01/01/1993",
  jackpot: 3000000
}

And, the same thing can be done with constructors in a few lines.

let scroogeTicket = new LotteryTicket("Ebenezer Scrooge", "01/05/1993", 8000000);
let timTicket = new LotteryTicket("Tiny Tim", "01/01/1993", 3000000);
let bobTicket = new LotteryTicket("Bob Cratchit", "01/01/1993", 3000000);

The above are almost equivalent ways of doing the same thing. One is a bit more casual than the other.

Accessing properties (variables vs. properties)

Variables are used in your program to store values. Properties are like variables. The difference is that properties are attached to an object. For example these are variables.

// variables
let y = 2;
let name = "Tim";
let d = new Date();

console.log(`Hello, ${name}! It is ${d}, and you are ${y} years old!`)
// prints "Hello, Tim! It is ___ and you are 2 years old!"

Here is something similar with and object. The properties of the objects can be accessed with dot notation.

let bobTicket = new LotteryTicket("Bob Cratchit", "01/01/1993", 3000000);
console.log("Hello, ${bobTicket.customerName}! Will you win the ${bobTicket.jackpot}?")
// prints "Hello Bob Cratchit! Will you win the 3000000?"

Object Methods

You can attach a function to an object. When a function is attached to an object, it’s called a method. The method can access all the properties on the object with the special variable called this. A good way to attach a method is to put it on the prototype of the constructor. For example:

// define the constructor
function LotteryTicket(customerName, datePurchased, jackpot) {
  this.customerName = customerName;
  this.datePurchased = datePurchased;
  this.jackpot = jackpot;
}

// set a method on the prototype
LotteryTicket.prototype.setLuckyNumbers = function() {
  let numbers = [];
  for (let i = 0; i < 5; i++) {
    let n = getRandomInt(1, 100);
    numbers.push(n);
  }
  this.luckNumbers = numbers;
}

let bobTicket = new LotteryTicket("Bob Cratchit", "1/1/1993", 3000000);
console.log(`The numbers for your ticket are ${bobTicket.luckNumbers}`);
// will print "The numbers for your ticket are undefined"

bobTicket.setLuckyNumbers();
console.log(`The numbers for your ticket are ${bobTicket.luckNumbers}`);
// will print "The numbers for your ticket are 55,22,87,34,21" (or other random numbers)

Can you see how we can use objects to collect data and use it?

Now we can make more tickets and set their lucky numbers:

let scroogeTicket = new LotteryTicket("Ebenezer Scrooge", "01/05/1993", 8000000);
let timTicket = new LotteryTicket("Tiny Tim", "01/01/1993", 3000000);
let bobTicket = new LotteryTicket("Bob Cratchit", "01/01/1993", 3000000);

let tix = [scroogeTicket, timTicket, bobTicket];

for(let ticket of tix) {
  ticket.setLuckyNumbers(); // invoke the method on each of the tix.
}

Let’s say that the winning numbers are:

let winningNumbers = [21, 34, 54, 98, 2];

Now lets make a method that will check for a winning ticket.

LotteryTicket.prototype.checkWinner = function(winning) {
  // go through each number
  for (let i = 0; i < winning.length; i++) {
    // Check if the number is a match
    // with the luckNumbers on our ticket.
    // Pay attention to the special `this` variable.
    if (this.luckNumbers[i] !== winning[i]) {
      // Set the property of winner on the object.
      this.winner = false;
      // Return false if any of the numbers are wrong.
      // This will also break out of the loop.
      return false;
    }
  }
  // If we haven't broken out of the loop, 
  // all the numbers must be right!
  this.winner = true;
  return true;
}

We can now invoke the method on all of our tickets with the dot notation.

let winningNumbers = [21, 34, 54, 98, 2];

// loop through all the numbers
for(let ticket of tix) {
  // invoke the method
  ticket.checkWinner(winningNumbers);
}

// loop again for our report
for(let ticket of tix) {
  if(ticket.winner) {
    // access properties
    alert(`${ticket.customerName} has won ${ticket.jackpot})
  }
}

Let see it all at once. You can copy and paste this code into a file or a Replit to see how it runs.

https://replit.com/@rmccrear/LotteryTicketObjectDemo#index.js

// lottery-ticket.js


// **** CODE FOR SET UP ****

function getRandomInt(min, max) {
  min = Math.ceil(min);
  max = Math.floor(max);
  return Math.floor(Math.random() * (max - min) + min); // The maximum is exclusive and the minimum is inclusive
}

// define the constructor
function LotteryTicket(customerName, datePurchased, jackpot) {
  this.customerName = customerName;
  this.datePurchased = datePurchased;
  this.jackpot = jackpot;
}

// set a method on the prototype
LotteryTicket.prototype.setLuckyNumbers = function() {
  let numbers = [];
  for (let i = 0; i < 5; i++) {
    let n = getRandomInt(1, 100);
    numbers.push(n);
  }
  this.luckNumbers = numbers;
}

LotteryTicket.prototype.checkWinner = function(winning) {
  // go through each number
  for (let i = 0; i < winning.length; i++) {
    // check if the number is a match
    // with the luckNumbers on our ticket.
    // pay attention to the special `this` variable
    if (this.luckNumbers[i] !== winning[i]) {
      // return false if any of the numbers are wrong
      // this will also break out of the loop
      this.winner = false;
      return false;
    }
  }
  // If we haven't broken out of the loop, 
  // all the numbers must be right!
  this.winner = true;
  return true;
}

// **** CODE WE EXECUTE ****
let scroogeTicket = new LotteryTicket("Ebenezer Scrooge", "01/05/1993", 8000000);
let timTicket = new LotteryTicket("Tiny Tim", "01/01/1993", 3000000);
let bobTicket = new LotteryTicket("Bob Cratchit", "01/01/1993", 3000000);

let tix = [scroogeTicket, timTicket, bobTicket];

// loop through all the numbers
// to set the lucky numbers
for (let ticket of tix) {
  ticket.setLuckyNumbers();
}

let winningNumbers = [21, 34, 54, 98, 2];

// loop through all the numbers
// to check for a winner
for (let ticket of tix) {
  ticket.checkWinner(winningNumbers);
}

// loop again for our report
for (let ticket of tix) {
  if (ticket.winner) {
    alert(`${ticket.customerName} has won ${ticket.jackpot}`)
  } else {
    alert(`${ticket.customerName} has not won ${ticket.jackpot}`)
  }
}

In this case, it will be almost impossible to get a winning ticket. Can you think of a way to make the lottery easier to win? Maybe by shortening the amount of numbers needed to win?

Tech words to pay attention to:

function
method
variable
property
invoke
object literal
constructor