Encapsulate state with the module pattern
Long before #private fields, the way to protect state was to keep it in a function's scope and return only the operations you wanted to allow. It is still the pattern behind most stores and SDK clients: the internals are unreachable, so every change goes through a method that can validate it.
Implement createAccount(initialBalance = 0). It returns an object with exactly four methods: deposit(amount) adds to the balance and returns the new balance; withdraw(amount) subtracts and returns the new balance; getBalance() returns the current balance; and getHistory() returns the recorded operations. The balance itself must not be an own property of the returned object, so its only own enumerable properties are those four methods. deposit and withdraw throw new Error("Invalid amount") when the amount is not greater than zero, and withdraw throws new Error("Insufficient funds") when the amount exceeds the balance; in both cases the balance is left unchanged and nothing is recorded. getHistory() returns a new array each time, holding one entry per successful operation in order, each of the form { type: "deposit", amount: 10 } or { type: "withdraw", amount: 5 } — mutating the returned array must not affect the account.
Arguments
initialBalancenumber- Starting balance. Defaults to
0.
Returns
{ deposit(amount): number; withdraw(amount): number; getBalance(): number; getHistory(): Array<{ type: 'deposit' | 'withdraw'; amount: number }> } — An account object exposing only the four methods — balance and history are private closures.
Examples
const account = createAccount(100);
account.deposit(50); // 150
account.withdraw(30); // 120
account.getBalance(); // 120const account = createAccount(20);
try { account.withdraw(50); } catch (e) { /* Insufficient funds */ }
account.getBalance(); // 20 — rejected operations leave state untouched
account.getHistory(); // [] — nothing was recordedValidate before mutating; the account never ends up half-updated.
What it has to do
depositandwithdrawreturn the new balance andgetBalance()agrees with them.- The returned object's only own enumerable properties are the four methods.
- Throw
Error("Invalid amount")for an amount that is not greater than zero. - Throw
Error("Insufficient funds")when a withdrawal exceeds the balance, leaving the balance unchanged. getHistory()returns a fresh array of{ type, amount }entries for successful operations only.
Notes
getHistory()must build a new array (and new entry objects) every call — returning the internal array hands callers a way to rewrite history.- Use
!(amount > 0)instead ofamount <= 0: it correctly rejectsNaN, which<=lets through.
Stuck? The javascript course covers everything this challenge needs.
- 1.deposits and withdraws
- 2.keeps the balance private
- 3.rejects an amount that is not positive
- 4.refuses to overdraw
- 5.history records successes only and is a copy
These assertions run in your browser the moment you hit Run. Pass all of them to claim the XP.
Discussion
Sign in to postNo comments yet. Be the first to say something.