Start learning free

LESSON 555 OF 569 · OBJECT-ORIENTED PROGRAMMING - CHALLENGES

Ticket Numbers in JavaScript: Static Members

Practice O(1) Read the full explanation

A ticket machine gives every new ticket the next number: the first ticket gets 1, the next one 2, and so on. The counter belongs to the class, not to any one ticket: it is a static member of Ticket, one copy shared by all the tickets. Each ticket keeps its own number, copied from the counter when the ticket is created.

Implement the class Ticket:

  • Ticket(name) creates a ticket for name. It adds 1 to the class-level counter and gives the new ticket that value as its number. The ticket keeps its name and its number in two fields, name and number.
  • The static method issued() returns how many tickets were created since the counter was last reset.
  • The static method resetCounter() sets the counter back to 0, so the next ticket gets number 1 again.

For each test case, the test code calls resetCounter() through the class name, then creates one ticket per name, in order. Once all the tickets of the case exist, it prints each ticket as its name, a space, # and its number, one ticket per line, and then the value of issued() on a line of its own.

The starter code spells these names the way your language does: reset_counter in Python, Issued and ResetCounter in C#. In Python the counter is a class attribute and the two methods are marked @staticmethod; in Kotlin and Scala the counter and the two methods live in the companion object, as in the Static Members lesson.

 

Example 1:

Input:
    Ticket("Ann")
    Ticket("Bob")
    Ticket("Cy")
Output:
Ann #1
Bob #2
Cy #3
3
Explanation: resetCounter() set the counter to 0. Each new ticket adds 1 to it and keeps the new value,
so the tickets get 1, 2 and 3, and issued() returns 3.

Example 2:

Input:
    Ticket("Mia")
    Ticket("Mia")
Output:
Mia #1
Mia #2
2
Explanation: The number comes from the shared counter, not from the name, so the two tickets for Mia
get different numbers. The numbers start at 1 again because resetCounter() ran before this case.

Example 3:

Input:
    (no tickets)
Output:
0
Explanation: resetCounter() set the counter to 0 and no ticket was created, so issued() returns 0.

 

Constraints:

  • A test case creates from 0 to 1000 tickets.
  • A name is one word of 1 to 20 English letters. Two tickets can have the same name.
  • The tickets are printed only after all of them were created, so every ticket must store its own number: reading the shared counter when printing would give every ticket the last number.
STEP 1 OF 6
    Ctrl + Enter to check

    JAVASCRIPT · OBJECT-ORIENTED PROGRAMMING - CHALLENGES

    Ticket Numbers in JavaScript, explained

    Problem overview

    A ticket machine gives every new ticket the next number: 1, then 2, and so on. The counter belongs to the class Ticket, not to any one ticket, so there is one copy shared by all of them. Each ticket keeps its own name and its own number.

    The class has three parts to write:

    • new Ticket(name) adds 1 to the shared counter and stores the new value as the ticket's number.
    • The static method Ticket.issued() returns how many tickets were created since the last reset.
    • The static method Ticket.resetCounter() sets the counter back to 0, so the next ticket is number 1 again.

    After a reset, tickets for Ann, Bob and Cy get the numbers 1, 2 and 3, and issued() returns 3. Two tickets for the same name still get different numbers, because the number comes from the counter, not from the name.

    Approach

    Most fields belong to an object: every Ticket has its own name. A static member belongs to the class itself. There is exactly one Ticket.count, no matter how many tickets exist, even none.

    The constructor does three things in order: store the name, increase the shared counter, and copy the counter's value into this.number. The copy matters. The counter keeps moving as more tickets are made, but a number is a plain value, so once it is copied into the ticket it stays there. Every operation takes O(1) time.

    Step by step

    1. Declare the counter. At the top of the class, write static count = 0;.
    2. Store the name. In the constructor, assign the parameter to this.name.
    3. Count the ticket. Increase Ticket.count by 1. A static field is always reached through the class name, even inside the class: this.count inside the constructor looks on the new ticket, not on the class.
    4. Keep the number. Set this.number to Ticket.count. The first ticket after a reset finds the counter at 1, so numbers start at 1.
    5. issued() is a static method that returns Ticket.count. Code calls it on the class, with no ticket at all, so it can only use static members.
    6. resetCounter() assigns 0 to Ticket.count.

    The solution in JavaScript

    class Ticket {
        static count = 0;
    
        constructor(name) {
            this.name = name;
            Ticket.count++;
            this.number = Ticket.count;
        }
    
        static issued() {
            return Ticket.count;
        }
    
        static resetCounter() {
            Ticket.count = 0;
        }
    }
    

    Using the class

    Ticket.resetCounter();
    const ts = ["Ann", "Bob", "Cy"].map(n => new Ticket(n));
    for (const t of ts) console.log(t.name + " #" + t.number);
    console.log(Ticket.issued());
    
    Ticket.resetCounter();
    const m = [new Ticket("Mia"), new Ticket("Mia")];
    for (const t of m) console.log(t.name + " #" + t.number);
    console.log(Ticket.issued());
    
    Ticket.resetCounter();
    console.log(Ticket.issued());
    

    This prints:

    Ann #1
    Bob #2
    Cy #3
    3
    Mia #1
    Mia #2
    2
    0
    

    The tickets for Ann, Bob and Cy still show 1, 2 and 3 after all of them exist. Each ticket holds its own copy of the number.

    Static members and instances

    A static member lives on the class and is not found on the objects. With the tickets above, ts[0].count is undefined, and so is ts[0].issued. The class name is the way in: Ticket.count and Ticket.issued().

    Common mistakes

    • Reading the counter later instead of copying it. If a ticket looked up Ticket.count whenever its number is needed, for example in a getter, every ticket would show the last number once all of them were created. With three tickets, a getter that reads the counter returns 3 for all of them. Copying the value in the constructor avoids this.
    • Using this.count. Inside the constructor, this is the new ticket. this.count++ would create a separate field on that ticket instead of changing the shared counter.
    • Increasing the counter after copying it. If the number is copied first and the counter is increased second, the first ticket gets 0.
    • Forgetting resetCounter(). The counter is shared by everything in the program, so without a reset a second group of tickets continues from where the first one stopped.

    Testing

    With no tickets created after a reset, Ticket.issued() returns 0. With one ticket created after a reset, its number is 1. Creating a ticket never changes the numbers of the tickets that already exist.

    Keep going with JavaScript500+ step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free