Start learning free

LESSON 559 OF 569 · OBJECT-ORIENTED PROGRAMMING - CHALLENGES

Shipping Options in JavaScript: Inheritance and Overriding

Practice O(1) Read the full explanation

An online shop offers three ways to ship a parcel. Standard shipping is the basic one. Express and Economy are kinds of shipping too: they answer the same two questions, what the option is called and what it costs, but each in its own way. So each one overrides the parent's methods with its own versions.

Implement the class Shipping, the standard option:

  • name() returns "Standard".
  • cost(weight) returns 5 + weight: a base price of 5, plus 1 for each kilogram.

and two classes that inherit from Shipping and override both methods:

  • Express: name() returns "Express", and cost(weight) returns 10 + 2 * weight.
  • Economy: name() returns "Economy", and cost(weight) returns 3 plus half the weight, rounded down to a whole number: half of 7 is 3.

The input lists parcels, one per line: the option (standard, express or economy) and the weight. For each line, the code that tests your classes creates that option and prints <name>: <cost> from its name() and cost(weight). The two calls are the same for every option (where variables have types, through a variable of the parent type Shipping); because the methods are overridden, each option answers with its own version. The starter code spells these names the way your language does.

 

Example 1:

Input:
    standard 4
    express 4
    economy 4
Output:
    Standard: 9
    Express: 18
    Economy: 5
Explanation: The same parcel of 4 kilograms costs 5 + 4 = 9 with Standard, 10 + 2 × 4 = 18 with Express
and 3 + 2 = 5 with Economy (half of 4 is 2).

Example 2:

Input:
    standard 0
    express 0
    economy 0
Output:
    Standard: 5
    Express: 10
    Economy: 3
Explanation: With a weight of 0, only the base prices are left.

Example 3:

Input:
    economy 7
    economy 1
    standard 7
    express 7
Output:
    Economy: 6
    Economy: 3
    Standard: 12
    Express: 24
Explanation: Economy halves the weight and rounds down: half of 7 is 3, so 3 + 3 = 6, and half of 1 is 0, so 3 + 0 = 3.

 

Constraints:

  • 0 <= weight <= 1000, a whole number of kilograms.
  • At most 100 parcels per test case.
STEP 1 OF 6
    Ctrl + Enter to check

    JAVASCRIPT · OBJECT-ORIENTED PROGRAMMING - CHALLENGES

    Shipping Options in JavaScript, explained

    Problem overview

    A shop ships parcels in three ways. Shipping is the standard option, and Express and Economy are kinds of shipping too. Every option answers the same two questions, name() and cost(weight), but each answers in its own way:

    Classname()cost(weight)
    Shipping"Standard"5 + weight
    Express"Express"10 + 2 * weight
    Economy"Economy"3 + weight / 2, rounded down

    For a parcel of 4 kilograms, Standard costs 5 + 4 = 9, Express costs 10 + 2 * 4 = 18, and Economy costs 3 + 4 / 2 = 5. With a weight of 0 only the base prices remain: 5, 10 and 3.

    Approach: a parent class and two subclasses

    The three options share a shape, two methods with the same names, so they share a parent. Express and Economy are written as class Express extends Shipping, which means an Express object is also a Shipping object. The subclass can then override a method: it declares a method with the same name, and JavaScript uses that version for objects of the subclass.

    The lookup works like this. When you call name() on an Express object, JavaScript looks for the method in Express first. It finds one, so it runs it. Only if Express had no name would JavaScript continue to Shipping. That is why a subclass that forgets to override cost silently charges the parent's price.

    The payoff comes at the call site. Code that holds a parcel's option can call option.name() and option.cost(weight) without knowing which class the option is, and each object answers with its own version.

    Step by step

    1. Write Shipping.name. It returns the text "Standard".
    2. Write Shipping.cost. It returns the base price 5 plus one per kilogram, 5 + weight.
    3. Override name in Express. Same header, new text: "Express".
    4. Override cost in Express. It returns 10 + 2 * weight. Without it, an express parcel would get the parent's 5 + weight.
    5. Override name in Economy. It returns "Economy". Each class overrides only for itself, so nothing here changes Express or Shipping.
    6. Override cost in Economy. It returns 3 plus half the weight, rounded down with Math.floor.

    The solution in JavaScript

    class Shipping {
        name() {
            return "Standard";
        }
    
        cost(weight) {
            return 5 + weight;
        }
    }
    
    class Express extends Shipping {
        name() {
            return "Express";
        }
    
        cost(weight) {
            return 10 + 2 * weight;
        }
    }
    
    class Economy extends Shipping {
        name() {
            return "Economy";
        }
    
        cost(weight) {
            return 3 + Math.floor(weight / 2);
        }
    }
    

    None of the three classes has a constructor, because the options store nothing: the price depends only on the weight passed to cost. JavaScript supplies a default constructor, so new Express() works.

    Why Math.floor is needed

    JavaScript has one number type, and / never rounds. 7 / 2 is 3.5, not 3. The lesson wants the division rounded down, so Economy.cost wraps it: Math.floor(7 / 2) is 3. Weights are never negative here, so rounding down and truncating agree.

    Using the classes

    Calling the methods through one list shows overriding at work:

    const options = [new Shipping(), new Express(), new Economy()];
    for (const option of options) {
        console.log(option.name() + ": " + option.cost(7));
    }

    This prints:

    Standard: 12
    Express: 24
    Economy: 6

    The loop body is identical for all three objects. Only the objects differ. Economy with a weight of 1 gives 3 + Math.floor(1 / 2), which is 3, and an Economy object is still a Shipping object: new Economy() instanceof Shipping is true.

    Why inheritance helps here

    Three unrelated classes would also work for the tests, because JavaScript does not check types before running. The difference is in what the code says. With extends Shipping, the program states that Express and Economy are kinds of shipping, and a reader knows that anything written for a Shipping object, such as a function that prints a quote, accepts them too. A fourth option, say overnight delivery, needs only another subclass that overrides the two methods.

    The overrides here replace the parent's code completely. The parent's cost is never run for an express parcel. Inside a method, super.cost(weight) would call the parent's version on purpose, but this lesson does not need it, because Express and Economy compute their price from scratch.

    Tracing Economy

    Economy is the only class where rounding matters. For weights 0, 1, 4 and 7, Math.floor(weight / 2) gives 0, 0, 2 and 3, so the costs are 3, 3, 5 and 6. Weights 6 and 7 give the same cost, 6, because the odd kilogram does not count.

    Edge cases and common mistakes

    • Forgetting one override. If Express overrides name but not cost, an express parcel of 4 kilograms costs 9, the standard price, and nothing reports an error. A subclass that only overrides name and is asked for cost(4) gets 9.
    • Dropping Math.floor. Without it, Economy with weight 7 returns 6.5 instead of 6, and any odd weight gives a fraction.
    • Misreading the order of operations. 10 + 2 * weight multiplies first, as in arithmetic. No parentheses are needed.
    • Weight 0. Every class returns just its base price: 5, 10 and 3.
    • Returning instead of printing. The methods return the name and the cost. The lesson's tests do the printing.

    Key takeaways

    • extends makes a subclass a kind of its parent.
    • A method with the same name in the subclass replaces the parent's for that class only.
    • Code that calls name() and cost(weight) works with any option, whichever class it is.
    Keep going with JavaScript500+ step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free