-
Notifications
You must be signed in to change notification settings - Fork 123
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
11 changed files
with
381 additions
and
38 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -40,19 +40,19 @@ When you're a developer at a big company your Monday could look something like t | |
```js | ||
const mondayTasks = [ | ||
{ | ||
name: "Daily standup", | ||
name: 'Daily standup', | ||
duration: 30, // specified in minutes | ||
}, | ||
{ | ||
name: "Feature discussion", | ||
name: 'Feature discussion', | ||
duration: 120, | ||
}, | ||
{ | ||
name: "Development time", | ||
name: 'Development time', | ||
duration: 240, | ||
}, | ||
{ | ||
name: "Talk to different members from the product team", | ||
name: 'Talk to different members from the product team', | ||
duration: 60, | ||
}, | ||
]; | ||
|
@@ -120,3 +120,177 @@ myPublisher.notify("Let's see what happens here!"); | |
// "let's see what happens here!" | ||
// "Let's see what happens here!" | ||
``` | ||
|
||
### Transfer into Wallet | ||
|
||
#### Folder: `ex5-wallet` | ||
|
||
In this exercise we will practice using the Chrome debugger. Other browsers, such as FireFox, Edge and Safari have similar tools but the exact look and feel may be different. | ||
|
||
At the end of the `index.js` file of the exercise is a `quiz` object with multiple-choice questions that we would like you to complete as you follow along the instructions below. | ||
|
||
> For a general tutorial on how to use the Chrome debugger see: [The definitive guide to JavaScript Debugging [2021 Edition]](https://dev.to/atapas/the-definitive-guide-to-javascript-debugging-2021-edition-116n). | ||
Here is a listing of the code in `index.js` (minus the `quiz` object) we will be working with: | ||
|
||
```js | ||
const eurosFormatter = new Intl.NumberFormat('nl-NL', { | ||
style: 'currency', | ||
currency: 'EUR', | ||
}); | ||
|
||
function createWallet(name, cash = 0) { | ||
function deposit(amount) { | ||
cash += amount; | ||
} | ||
|
||
function withdraw(amount) { | ||
if (cash - amount < 0) { | ||
console.log(`Insufficient funds!`); | ||
return 0; | ||
} | ||
|
||
cash -= amount; | ||
return amount; | ||
} | ||
|
||
function transferInto(wallet, amount) { | ||
console.log( | ||
`Transferring ${eurosFormatter.format(amount)} from ${name} to ${ | ||
wallet.name | ||
}` | ||
); | ||
const withdrawnAmount = withdraw(amount); | ||
wallet.deposit(withdrawnAmount); | ||
} | ||
|
||
function reportBalance() { | ||
console.log(`Name: ${name}, balance: ${eurosFormatter.format(cash)}`); | ||
} | ||
|
||
const getName = () => name; | ||
|
||
return { | ||
deposit, | ||
withdraw, | ||
transferInto, | ||
reportBalance, | ||
getName, | ||
}; | ||
} | ||
|
||
const walletJack = createWallet('Jack', 100); | ||
const walletJoe = createWallet('Joe', 10); | ||
const walletJane = createWallet('Jane', 20); | ||
|
||
walletJack.transferInto(walletJoe, 50); | ||
walletJane.transferInto(walletJoe, 25); | ||
|
||
walletJane.deposit(20); | ||
walletJane.transferInto(walletJoe, 25); | ||
|
||
walletJack.reportBalance(); | ||
walletJoe.reportBalance(); | ||
walletJane.reportBalance(); | ||
``` | ||
|
||
Since this is a browser-based exercise, the file `index.js` will be loaded via a `<script>` tag in `index.html`. The `index.html` file itself requires no further consideration here. | ||
|
||
Let's run the exercise using our convenience command `npm run it`: | ||
|
||
```console | ||
❯ npm run it | ||
|
||
> [email protected] it C:\Users\jimcr\dev\hackyourfuture\homework | ||
> node ./test-runner/run-it | ||
|
||
? Rerun last test (1-Javascript, Week4, ex5-wallet)? No | ||
? Which module? 1-Javascript | ||
? Which week? Week4 | ||
? Which exercise? ex5-wallet | ||
Running exercise, please wait... | ||
HTTP server running at http://localhost:3030 | ||
Press Ctrl-C to exit. | ||
``` | ||
|
||
This will run the exercise in the default browser (if your default browser is not Chrome then open this URL manually in Chrome: `http://locahost:3030`). | ||
|
||
Next, open the Developer Tools by pressing function key <kbd>F12</kbd> and examine the console output. It will look like this: | ||
|
||
```console | ||
Transferring € 50,00 from Jack to undefined | ||
Transferring € 25,00 from Jane to undefined | ||
Insufficient funds! | ||
Transferring € 25,00 from Jane to undefined | ||
Name: Jack, balance: € 50,00 | ||
Name: Joe, balance: € 85,00 | ||
Name: Jane, balance: € 15,00 | ||
``` | ||
|
||
We seem to have a bug because we get `undefined` where we expect a name. We would like to investigate the state of the program at the point where we get the message `Insufficient funds!`. | ||
|
||
Open the **Sources** panel from Developer Tools. Select `index.js` from the explorer panel and make sure that the console output is visible in the bottom panel, as shown in Figure 1. | ||
|
||
>  | ||
> | ||
> Figure 1. The Chrome Developer Tools Debugger. | ||
First let's examine what causes the `undefined` value in the message. The `console.log` that outputs that message starts on line 26. We would like to inspect the state of the program when the execution reaches that point. For that purpose we will place a **breakpoint** at line 26. A breakpoint is a location in our code where we would like the JavaScript engine to pause execution when we run the program with the debugger. | ||
|
||
To place a breakpoint at line 26, click to the left of the number 26 in the left margin of the editor window. A blue marker will appear to indicate the presence of a breakpoint (Figure 2): | ||
|
||
>  | ||
> | ||
> Figure 2. Breakpoint placed at line 26. | ||
With this breakpoint set, reload the page to rerun the JavaScript code. The execution will be paused at line 26, as indicated by the blue highlighting of that line: | ||
|
||
>  | ||
> | ||
> Figure 3. Breakpoint at line 26 is hit. | ||
To the right of the code panel you can inspect, amongst others, **Breakpoints**, **Scope** and the **Call Stack**. | ||
|
||
:question: Please answer questions **q1** and **q2** in the `quiz` object. | ||
|
||
When we expand the variable `wallet` in the local scope of the Scope panel, we can see that it contains the following properties (all functions): | ||
|
||
- `deposit` | ||
- `getName` | ||
- `reportBalance` | ||
- `transferInto` | ||
- `withdraw` | ||
|
||
There is no `name` property there. That must be the reason why we get `undefined` when we try to access `wallet.name`. Let's examine this by instructing the debugger to step over (i.e. execute) the `console.log` function call. Figure 4 below shows the debug buttons located near the upper right corner of the Developer Tools. | ||
|
||
>  | ||
> | ||
> Figure 4. Developer Tools debug buttons | ||
Hover the mouse over each of these buttons in the browser and take note of the tooltips that appear. | ||
|
||
:question: Please answer question **q3** of the `quiz` object. | ||
|
||
Press the button **Stepping over next function call**. As you can see the execution is now stopped at line 31. The whole function call, which spanned (due to Prettier) four lines is executed and stepped over. If we examine the console at the bottom of the screen we can see that the variable `name` was displayed correctly, but `wallet.name` was undefined. As we saw earlier in the Scope panel, a `wallet` object doesn't include a `name` property. | ||
|
||
The `name` variable, as well as the `cash` variable are deliberately made _private_ to each instance of a `wallet` object, by means of a _closure_. We don't want to give external code the ability to change the name of the wallet owner or change its cash amount. However, we _do_ want to give some form of **read-only** access to these variables. For this purpose the `wallet` object provides two functions, `reportBalance()` and `getName()`, that _do_ have access to the "_closed-in_" variables (or actually, in this case, _parameters_) `name` and `cash`. We can therefore fix the `undefined` bug by replacing `wallet.name` with `wallet.getName()`. | ||
|
||
Let's try and make that change in the VSCode editor window. Prettier will probably now cause the `console.log` call to span five lines. | ||
|
||
Now, with the breakpoint still set at line 26, reload the page (first click the large X to cancel loading the current page and then the reload button to reload the page). Then, step over the `console.log` and inspect the console. | ||
|
||
:question: Please answer question **q4** of the quiz object. | ||
|
||
With execution paused at (now) line 31, press the **Step into next function call** button. If all is well that should take us into the function `withdraw()`, which is being called from line 31. If you hover your mouse over the variables `cash` and `amount` on line 31 you can peek at their current values, respectively `100` and `50`: that should be sufficient to make the withdrawal successful. | ||
|
||
Let's add a breakpoint at line 17. That breakpoint will only be hit in the case of insufficient funds. Press the button **Step over next function call**. What is being stepped over here is not a function call but a statement. So maybe this button is better labelled "Step over next statement"... But we will have to make do with what we got. | ||
|
||
In any case, the `console.log` of line 17 was not executed, as we expected. | ||
|
||
With the `undefined` problem solved, we would now like to examine the instances where we get the message `Insufficient funds!`. The breakpoint at line 17 is perfect for that. But we no longer need the breakpoint at line 26. Click on that breakpoint in the left margin of the editor window to remove it again. | ||
|
||
Now, let's resume execution of the code by pressing the button **Resume script execution**. Our breakpoint at line 17 will be hit. Inspect the Scope panel to determine the name of the owner of the wallet that has insufficient funds. | ||
|
||
:question: Please answer question **q5** of the `quiz` object. | ||
|
||
Press the **Resume script execution** again. The program will now run to completion without issues. This also completes this exercise. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="UTF-8" /> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||
<title>Wallet App</title> | ||
<link | ||
rel="stylesheet" | ||
href="https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/4.0.0/github-markdown.min.css" | ||
integrity="sha512-Oy18vBnbSJkXTndr2n6lDMO5NN31UljR8e/ICzVPrGpSud4Gkckb8yUpqhKuUNoE+o9gAb4O/rAxxw1ojyUVzg==" | ||
crossorigin="anonymous" | ||
/> | ||
<style> | ||
.markdown-body { | ||
box-sizing: border-box; | ||
min-width: 200px; | ||
max-width: 980px; | ||
margin: 0 auto; | ||
padding: 45px; | ||
} | ||
|
||
@media (max-width: 767px) { | ||
.markdown-body { | ||
padding: 15px; | ||
} | ||
} | ||
</style> | ||
</head> | ||
<body> | ||
<article class="markdown-body"> | ||
<p> | ||
Open the Developer Console by pressing function key <kbd>F12</kbd>, to | ||
view the console output and use the debugger. | ||
</p> | ||
</article> | ||
<script src="index.js"></script> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
'use strict'; | ||
|
||
// Based on an example from: Philipp Beau (@ze_german) | ||
|
||
const eurosFormatter = new Intl.NumberFormat('nl-NL', { | ||
style: 'currency', | ||
currency: 'EUR', | ||
}); | ||
|
||
function createWallet(name, cash = 0) { | ||
function deposit(amount) { | ||
cash += amount; | ||
} | ||
|
||
function withdraw(amount) { | ||
if (cash - amount < 0) { | ||
console.log(`Insufficient funds!`); | ||
return 0; | ||
} | ||
|
||
cash -= amount; | ||
return amount; | ||
} | ||
|
||
function transferInto(wallet, amount) { | ||
console.log( | ||
`Transferring ${eurosFormatter.format(amount)} from ${name} to ${ | ||
wallet.name | ||
}` | ||
); | ||
const withdrawnAmount = withdraw(amount); | ||
wallet.deposit(withdrawnAmount); | ||
} | ||
|
||
function reportBalance() { | ||
console.log(`Name: ${name}, balance: ${eurosFormatter.format(cash)}`); | ||
} | ||
|
||
const getName = () => name; | ||
|
||
return { | ||
deposit, | ||
withdraw, | ||
transferInto, | ||
reportBalance, | ||
getName, | ||
}; | ||
} | ||
|
||
const walletJack = createWallet('Jack', 100); | ||
const walletJoe = createWallet('Joe', 10); | ||
const walletJane = createWallet('Jane', 20); | ||
|
||
walletJack.transferInto(walletJoe, 50); | ||
walletJane.transferInto(walletJoe, 25); | ||
|
||
walletJane.deposit(20); | ||
walletJane.transferInto(walletJoe, 25); | ||
|
||
walletJack.reportBalance(); | ||
walletJoe.reportBalance(); | ||
walletJane.reportBalance(); | ||
|
||
// * End of exercise code | ||
|
||
/******************************************************************************* | ||
* TODO: Multiple choice: provide your answers by replacing `undefined` with the | ||
* TODO: letter corresponding to your choice, e.g. answer: 'a' | ||
******************************************************************************/ | ||
// prettier-ignore | ||
// eslint-disable-next-line no-unused-vars | ||
const quiz = { | ||
q1: { | ||
question: 'At line 26, which variables are in the scope marked Closure?', | ||
choices: { | ||
a: 'There is no scope marked Closure', | ||
b: 'cash, name', | ||
c: 'amount, this, wallet' | ||
}, | ||
answer: undefined, | ||
}, | ||
q2: { | ||
question: 'What is in the Call Stack, from top to bottom?', | ||
choices: { | ||
a: 'withdraw, anonymous', | ||
b: 'anonymous, transferInto', | ||
c: 'transferInto, anonymous' | ||
}, | ||
answer: undefined, | ||
}, | ||
q3: { | ||
question: 'What tooltip appears when hovering over the third debug button?', | ||
choices: { | ||
a: 'Step into next function call', | ||
b: 'Step out of current function', | ||
c: 'Step' | ||
}, | ||
answer: undefined, | ||
}, | ||
q4: { | ||
question: 'What is displayed in the console?', | ||
choices: { | ||
a: 'Transferring € 50,00 from Jack to Joe', | ||
b: 'Transferring € 50,00 from Jack to undefined', | ||
c: 'Transferring € 50,00 from Jack to Jane' | ||
}, | ||
answer: undefined, | ||
}, | ||
q5: { | ||
question: 'The owner of the wallet with insufficient funds is:', | ||
choices: { | ||
a: 'Jack', | ||
b: 'Joe', | ||
c: 'Jane' | ||
}, | ||
answer: undefined, | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
This test has not been run. |
Oops, something went wrong.