Functions
So far every program has run from top to bottom, once. A function is a piece of program with a name, which you can run whenever you like, as often as you like, with different values each time. Functions are how programs avoid saying the same thing twice.
Making your own
Here is a function called double. It takes a number and gives back twice that number:
function double(n: 0) {
return n * 2
}
preview.append(`Double 21 is ${double(21)}.`)
test 'double doubles' {
expect(double(21)).toBe(42)
expect(double(0)).toBe(0)
}
Read it a line at a time:
function double(…)gives the function its name.nis a parameter: a name for the value the function is given. Each time the function runs,nis whatever value it was handed.return n * 2gives the answer back to whoever asked.double(21)calls the function: it runs it withnset to 21, and the call becomes the answer, 42.
What : 0 means
The : 0 after n says what kind of value n should be, by giving an example of one:
0 is a whole number, so double expects a whole number. The example is not a default and
not a special value; any whole number will do.
Because TJS knows what double expects, it checks every call. Try these at the console's
prompt:
function double(n: 0) {
return n * 2
}
console.log('Try double(5), then double(2.5), then double("ten").')
double(5) is 10. double(2.5) and double("ten") do not run the function at all: the
answer is an error saying what was expected and what arrived, instead of a nonsense
result that would cause trouble later. If you want a function that takes any number,
fractions included, give it the example 0.0 instead.
Several parameters
A function can take more than one value. Separate the parameters with commas, and give the values in the same order when you call it:
function area(width: 0, height: 0) {
return width * height
}
preview.append(`A 6 by 7 rectangle has an area of ${area(6, 7)}.`)
test 'area multiplies' {
expect(area(6, 7)).toBe(42)
expect(area(1, 1)).toBe(1)
}
Words in, words out
Parameters can be any kind of value. This one takes a name ('Ada' is the example, so the
parameter is a string) and gives back a sentence:
function greet(name: 'Ada') {
return `Hello, ${name}!`
}
preview.append(greet('Grace'))
test 'greet puts the name in the middle' {
expect(greet('Grace')).toBe('Hello, Grace!')
}
The example is also a test
You can give an example for the answer too, after the parentheses:
function greet(name: 'Ada'): 'Hello, Ada!' {
return `Hello, ${name}!`
}
preview.append(greet('Katherine'))
test 'greet works for other names too' {
expect(greet('Grace')).toBe('Hello, Grace!')
}
The first line now reads: "given 'Ada', greet returns 'Hello, Ada!'". That documents
the function, and it is a test as well: TJS runs greet('Ada') and checks the answer. The
result line counts it beside the test below. Change 'Hello, Ada!' to 'Hi, Ada!' and the
line turns red, saying greet('Ada') actually returned 'Hello, Ada!'.
Values that can be left out
Write = instead of : to give a parameter a default: the value it gets when the caller
leaves it out.
function greet(name = 'friend') {
return `Hello, ${name}!`
}
preview.append(greet(), ' ', greet('Ada'))
test 'a default fills the gap' {
expect(greet()).toBe('Hello, friend!')
expect(greet('Ada')).toBe('Hello, Ada!')
}
: means "you must give me one of these"; = means "you may, and here is what I use if you
don't". The default is an example too, so greet still only takes strings.
Try it
Write a function minutes(hours: 0) that gives back how many minutes are in that many hours.
Show a sentence using it, and add a test that checks minutes(2) is 120. Then give it a
second parameter, extraMinutes = 0, so that minutes(1, 30) is 90, and test that too.