Start learning free

LESSON 557 OF 569 · OBJECT-ORIENTED PROGRAMMING - CHALLENGES

Inventory Item Class in JavaScript: Private Stock

Practice O(1) Read the full explanation

A shop keeps track of how many pieces of each item it has: the item's stock. The stock can never go below 0, and it changes only when pieces are sold or new ones arrive. So the stock is a private field, changed only through two methods that check the rules. The item's name has no rules to protect, so it stays a field any code can read.

Implement the class InventoryItem:

  • InventoryItem(name, stock) creates an item with that name and that many pieces in stock. The name is kept in a field name that other code can read.
  • sell(n) sells n pieces. If n is at least 1 and at most the stock, it lowers the stock by n and returns true. Otherwise it changes nothing and returns false: selling 0 pieces, a negative number of pieces, or more pieces than there are in stock is refused.
  • restock(n) adds n pieces to the stock when n is at least 1, and ignores n otherwise. It returns nothing.
  • getStock() returns the stock. It is the only way for other code to read it.

Keep the stock private the way the Access Modifiers lesson does in your language: self._stock in Python (private by convention), a #stock field in JavaScript, and the private keyword in Java, C++, C#, TypeScript, Kotlin, Scala and Swift. In Kotlin and Scala the constructor's second parameter is named initialStock, and the private stock starts at its value.

Each test case creates one item, then applies a list of operations to it, in order. The output has one line per test case: the item's name and a colon, then what each sell and getStock call returns, separated by spaces, with sell's answer printed as True or False. The starter code spells these names the way your language does: get_stock in Python, Sell, Restock and GetStock in C#.

 

Example 1:

Input:
    InventoryItem("Pencil", 5)
    sell(3)
    getStock()
    sell(5)
    getStock()
    restock(10)
    getStock()
Output: Pencil: True 2 False 2 12
Explanation: Selling 3 of the 5 pencils works and leaves 2. Selling 5 more is refused, because only 2 are left,
and the stock stays 2. restock(10) brings it to 12.

Example 2:

Input:
    InventoryItem("Mug", 4)
    sell(4)
    getStock()
    sell(1)
    getStock()
Output: Mug: True 0 False 0
Explanation: Selling all 4 mugs is allowed and leaves 0. With nothing left, even one mug can't be sold.

Example 3:

Input:
    InventoryItem("Lamp", 2)
    sell(0)
    sell(-3)
    restock(0)
    restock(-5)
    getStock()
    restock(1)
    sell(3)
    getStock()
Output: Lamp: False False 2 True 0
Explanation: Selling 0 or -3 lamps is refused, and restocking 0 or -5 lamps is ignored, so the stock is still 2.
After restock(1) there are 3 lamps, and selling all 3 works.

 

Constraints:

  • A name is one word of English letters. 0 <= stock <= 104 when the item is created.
  • -104 <= n <= 104 in every sell and restock.
  • A test case has from 1 to 1000 operations, and at least one of them is a sell or a getStock.
STEP 1 OF 6
    Ctrl + Enter to check

    JAVASCRIPT · OBJECT-ORIENTED PROGRAMMING - CHALLENGES

    Inventory Item in JavaScript, explained

    Problem overview

    A shop tracks how many pieces of each item it has. The stock can never go below 0, and it changes only when pieces are sold or new ones arrive. So the stock is a private field, #stock, changed only through two methods that check the rules. The item's name has no rules to protect, so it stays an ordinary field that any code can read.

    • new InventoryItem(name, stock) creates an item with that name and that many pieces.
    • sell(n) sells n pieces. If n is at least 1 and at most the stock, it lowers the stock by n and returns true. Otherwise it changes nothing and returns false: selling 0, a negative number, or more than is in stock is refused.
    • restock(n) adds n pieces when n is at least 1 and ignores other values. It returns nothing.
    • getStock() returns the stock, and is the only way to read it.

    For a pencil item with stock 5: sell(3) works and leaves 2, sell(5) is refused because only 2 are left, and restock(10) brings the stock to 12.

    Approach

    Each method guards the stock before touching it. In sell, the check comes first and the change second, so a refused sale leaves everything as it was. Because the check says n is at most the stock, the stock after a sale is at least 0. In restock, a delivery of 0 or less is not a delivery, so it is skipped. Everything runs in O(1) time.

    Step by step

    1. Declare the private field. At the top of the class, write #stock;.
    2. Store both values. In the constructor, this.name gets the name and this.#stock gets the stock. The name is a normal public field.
    3. Refuse bad sales. In sell, an if for n < 1 || n > this.#stock returns false. The value of n equal to the stock is allowed: the shop may sell everything it has.
    4. Make the sale. After the if, subtract n from this.#stock and return true. Only sales that passed the check reach this line.
    5. Restock. If n >= 1, add n to the stock. Otherwise do nothing.
    6. Read. getStock() returns this.#stock.

    The solution in JavaScript

    class InventoryItem {
        #stock;
    
        constructor(name, stock) {
            this.name = name;
            this.#stock = stock;
        }
    
        sell(n) {
            if (n < 1 || n > this.#stock) {
                return false;
            }
            this.#stock -= n;
            return true;
        }
    
        restock(n) {
            if (n >= 1) {
                this.#stock += n;
            }
        }
    
        getStock() {
            return this.#stock;
        }
    }
    

    Using the class

    let item = new InventoryItem("Pencil", 5);
    console.log(item.name + ":", item.sell(3), item.getStock(), item.sell(5), item.getStock());
    item.restock(10);
    console.log(item.getStock());
    
    item = new InventoryItem("Mug", 4);
    console.log(item.name + ":", item.sell(4), item.getStock(), item.sell(1), item.getStock());
    
    item = new InventoryItem("Lamp", 2);
    console.log(item.sell(0), item.sell(-3));
    item.restock(0);
    item.restock(-5);
    console.log(item.getStock());
    item.restock(1);
    console.log(item.sell(3), item.getStock());
    console.log(item.stock, item.name);
    

    This prints:

    Pencil: true 2 false 2
    12
    Mug: true 0 false 0
    false false
    2
    true 0
    undefined Lamp
    

    The lesson's tests print the booleans as True and False; JavaScript itself prints true and false. The last line shows the difference between the two fields: item.name is readable, while item.stock is undefined, because the stock is stored under the private name #stock and the only way to see it is getStock().

    Why the check is written that way

    The condition has two halves, joined with ||: the sale is refused if n < 1 or n > this.#stock. Both halves are needed. Without the first, sell(-2) would pass the second and add two pieces, because subtracting a negative number adds. A version that only checks n > this.#stock shows it: on an item with stock 3, sell(-2) returns true and the stock becomes 5. Without the second half, selling 4 pieces of 3 would push the stock to -1.

    Common mistakes

    • Changing the stock before checking. The refusal must come first, or a refused sale would still change the stock.
    • Using >= for the upper limit. Selling exactly the stock is allowed. With n >= this.#stock, selling the last pieces would be refused.
    • Letting restock take 0 or negative values. restock(-5) would remove pieces without any of sell's checks.
    • Returning something from restock. It returns nothing. A caller that prints its result sees undefined.
    • Making the name private as well. The statement keeps the name readable. Private fields are for values with rules to protect.

    Testing the edges

    On an item with stock 3 (a cup), these calls run in order:

    CallResultStock after
    sell(4)false3
    sell(3)true0
    sell(0)false0
    sell(-1)false0
    restock(0)nothing0
    restock(-4)nothing0
    restock(7)nothing7

    Selling more than is in stock, selling exactly what is in stock, and selling nothing each behave differently, so they are worth a test of their own. A new item can also start with a stock of 0. Then every sell is refused until a restock brings the stock to 1 or more.

    Public name, private stock

    The class has two kinds of data on purpose. The name can be anything and nothing depends on it, so a plain this.name is enough, and code outside can read it or even change it. The stock has a rule: it must never go below 0. A private field makes that rule enforceable, because every change has to go through sell or restock. If the stock were public, any line of code could write item.stock = -50 and the class could do nothing about it. With #stock, the same line does not touch the real stock, and the item keeps answering with the correct number.

    Use a private field when a value has a rule to protect, and keep the rest public. A class where everything is private is harder to use for no benefit.

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