Input and output
Problem
The program knows only one name
The program greets the customer by name:
const name = "Maria";console.log("Hello, " + name + "!");Hello, Maria!It works, but it greets everyone as Maria. The name is written in the code. For every new customer you have to change the program and run it again. You want the program to ask on its own.
The idea
Reading from the keyboard
When the program reads, it stops and waits. The person types and presses Enter. What they type is the program's input.
import { createInterface } from "node:readline";
const rl = createInterface({ input: process.stdin });const lines = rl[Symbol.asyncIterator]();async function ask(question) { process.stdout.write(question); return (await lines.next()).value;}
const name = await ask("What is your name? ");console.log("Hello, " + name + "!");rl.close();MariaWhat is your name? Hello, Maria!JavaScript has no short, ready command for reading from the keyboard. So a few lines at the top make a helper: ask. ask("What is your name? ") prints the question, waits for the person to type a line and press Enter, and gives back what they typed. await in front of it means "wait for the answer". rl.close(); at the end closes the reading when the program will not read anymore.
You will learn what import, async, function and await mean later. Functions are in the "Functions" module. For now, copy these lines to the top of every program that reads. Later in the lessons we do not show them, only the lines after them.
The input and the output are shown separately here. In the console the name appears where you type it: after "What is your name? ". ask prints the question with process.stdout.write, without a new line: the answer is on the same line.
More precisely, if you are curious
ask("")with empty quotes only reads, with no question.- If the input has ended (there are no more lines),
askgivesundefined, "no value". readlinealso hasrl.question(), which you will see in examples online. When the input comes from a file, it loses lines, so we do not use it here.
Problem
12 + 30 = 1230
The cashier enters two payments, €12 and €30. The program has to show the total:
const first = await ask("");const second = await ask("");const total = first + second;console.log("Total: €" + total);rl.close();1230Total: €1230Instead of 42 you got 1230. The program did not get the math wrong. It did no math at all.
There is no question here: ask("") only reads a line.
The idea
From text to a number
Whatever the person types, ask() returns text. "12" and "30" are two texts, and + between texts glues them together. To do math, turn the text into a number:
const first = Number(await ask(""));const second = Number(await ask(""));const total = first + second;console.log("Total: €" + total);rl.close();1230Total: €42Turning text into a value of another type is called parsing.
Number(...)gives a number, whole or decimal: in JavaScript they are one type.- There are also
parseInt(...)andparseFloat(...). They read the digits at the start of the text and stop at the first other character:parseInt("12 €")is 12.
The sum here is the first calculation in the course. Subtraction, multiplication and division come in the next lesson.
const first = Number(await ask(""));const second = Number(await ask(""));const total = first + second;console.log("Total: €" + total);rl.close();Step by step, in words
- The person types 12 and Enter. await ask("") returns the text "12", not a number.
- Number turns the text into the number 12. It goes into first.
- 30 takes the same path: text, parsing, a number in second.
- Now + adds numbers: 12 + 30 = 42.
- It prints "Total: €42".
More precisely, if you are curious
- If the text is not a number (for example "twelve"), JavaScript does not stop.
NumbergivesNaN(Not a Number), and math withNaNgivesNaNagain. An empty line gives 0. Spaces around it do not matter:Number(" 12 ")is 12.
console.log(Number(" 12 "));console.log(Number("3.5"));console.log(Number("twelve"));console.log(Number("3,5"));console.log(Number(""));console.log(Number("twelve") + 1);123.5NaNNaN0NaNNumberalways wants a point, whatever the computer's settings:Number("3,5")isNaN.
Try it
How many tickets?
The program reads how many adults and how many children there are.
23What will the program print?
const adults = Number(await ask(""));const children = Number(await ask(""));console.log("Tickets: " + adults + children);rl.close();"Tickets: " + adults is already the text "Tickets: 2", and text + 3 glues 3 onto the end. With parentheses the sum is done first: "Tickets: " + (adults + children) gives "Tickets: 5".The idea
Numbers the way you want them
In the last lesson the price 49.90 came out as 49.9. For a price you always want two digits after the decimal point. This is formatted output:
const product = "Headphones";const price = 49.9;const qty = 2;console.log(`${product}: €${price.toFixed(2)}`);console.log(`${qty} in the cart`);const label = `Price: €${price.toFixed(2)}`;console.log(label);Headphones: €49.902 in the cartPrice: €49.90Text in backticks, `, is a template literal: you write the values right inside it, in ${…}. This is called string interpolation.
price.toFixed(2) gives the number as text with exactly 2 digits after the point. toFixed(0) has no digits after the point, toFixed(3) has three.
The value in the variable does not change. The format only decides how it looks when it is printed.
More precisely, if you are curious
- Thousands separators and lining up in columns:
const total = 1234.5;console.log("Total: €" + total.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 }));console.log("Coffee".padEnd(10) + "|" + (2.5).toFixed(2).padStart(8));console.log("Laptop".padEnd(10) + "|" + (1299.0).toFixed(2).padStart(8));Total: €1,234.50Coffee | 2.50Laptop | 1299.00toLocaleString("en-US", …) writes the number by the rules of US English, with a thousands separator. padEnd(10) fills the text with spaces on the right up to 10 characters, and padStart(8) on the left up to 8.
- toFixed does not follow the regional settings: a point stays a point on every computer. If you want a decimal comma, the way it is written in Bulgaria and much of Europe, add it yourself:
const price = 49.9;console.log("Price: €" + price.toFixed(2).replace(".", ","));Price: €49,90Try it
Two digits
A night at the hotel costs €65.5. You want it to come out as "Per night: €65.50". What goes in the blank?
console.log(`Per night: €${price.}`);toFixed(2): a decimal number with exactly two digits after the point.
Try it
Find the bug
12 tickets are already reserved, and the program adds as many more as you enter. With input 4 it prints "Reserved: 124". Which line is the bug on?
Pick the line with the bug.
ask returns text, "4". 12 + "4" is not an error in JavaScript: the number is turned into text and the two are glued into "124". That is why you catch a slip like this by looking at the output. The fix is const tickets = Number(await ask("Number of tickets: "));.Exercise
Programs that ask
Solve the tasks in your editor. The input is one line for each value. Do not print questions like "Enter a name:", so your output matches the sample: write ask("").
1. Greeting by name. Read a name and greet the person.
MariaHello, Maria!2. Sum of two numbers. Read two whole numbers and print the calculation.
172517 + 25 = 423. Two texts in one. Read two texts and print them together, with a space between them.
VelikoTarnovoVeliko Tarnovo4. π with two digits. Store π in a variable as 3.14159265358979 and print it with two digits after the point. The ready value Math.PI comes in the next lesson.
3.14More tasks
- Age. Read a name and an age (a whole number) and print "Maria is 19 years old."
- A business card from the keyboard. Read a name, a job and a phone number and print the business card from the "Your first program" lesson with them.
- A price with two digits. Read a price as a decimal number and print it with two digits and the euro sign: for input
7.5the output isPrice: €7.50. - Sum of two prices. Read two decimal prices and print their sum with two digits: for input
12.4and3.15the output isTotal: €15.55.
Test