drawLine(10, 20, 30, 40, 'blue');
Draws a blue line from x,y coordinates 10,20
to
30,40
We don’t have to know how it works, just what it does.
Using it like this is described as “calling” it.
As in, “Call the drawLine
function to draw a line.”
The stuff in ()
s after the name of the function in a
function call is a comma-delimited list of expressions.
The expressions are each evaluated to get a list of values that are “passed” to the function.
The values are called the “arguments” to the function.
As in “We passed the arguments 10
, 20
,
30
, 40
, and 'blue'
to the
drawLine
function.”
Math.random()
⟹ 0.7388842248424481
We still need the ()
s to indicate that we’re calling
the function.
drawLine(10, 20, 30, 40, 'blue');
drawLine(30, 40, 50, 60, 'blue');
drawLine(50, 60, 10, 20, 'blue');
Note how these three calls to drawLine
add up to a
triangle by connecting the three points 10,20
,
30,40
, and 50,60
.
drawLine(10, 20, 30, 40, 'blue');
drawLine(30, 40, 10, 40, 'blue');
drawLine(10, 40, 10, 20, 'blue');
Same pattern but maybe a bit harder to see because of the common x and y values in some of the points.
let x1 = 10;
let y1 = 20;
let x2 = 30;
let y2 = 40;
let x3 = 50;
let y3 = 60;
The names could be anything.
But we should choose names that suggest their purpose.
Using variables as the arguments to drawLine
make the
pattern a bit easier to see.
drawLine(x1, y1, x2, y2, 'blue');
drawLine(x2, y2, x3, y3, 'blue');
drawLine(x3, y3, x1, y1, 'blue');
With the variable definitions just given, this draws the first triangle.
// Variables already exist, just give them new values
x1 = 10;
y1 = 20;
x2 = 30;
y2 = 40;
x3 = 10;
y3 = 40;
drawLine(x1, y1, x2, y2, 'blue');
drawLine(x2, y2, x3, y3, 'blue');
drawLine(x3, y3, x1, y1, 'blue');
Note that these three lines are exactly the same as before.
We can mentally “chunk” the three lines of code that draw the triangle so whenever we see them, we know what’s happening.
And the use of variables in the calls to drawLine
make
the pattern a bit more clear.
The obvious one is the massive duplication of code.
Even worse is the lack of abstraction: we know the three calls to
drawLine
mean “draw a triangle” but we have to look at
the details of the code to really see it.
Need to make sure no other code is using those variable names.
const drawTriangle = (x1, y1, x2, y2, x3, y3) => {
drawLine(x1, y1, x2, y2, 'blue');
drawLine(x2, y2, x3, y3, 'blue');
drawLine(x3, y3, x1, y1, 'blue');
};
This is defining a variable named drawTriangle
whose
value is a function.
There’s a lot going on here so let’s take it apart.
The first thing is just a normal variable definition …
const drawTriangle = ...
… defining a variable named drawTriangle
whose value,
once set, will never change.
The value we assign to that variable is this:
(x1, y1, x2, y2, x3, y3) => {
drawLine(x1, y1, x2, y2, 'blue');
drawLine(x2, y2, x3, y3, 'blue');
drawLine(x3, y3, x1, y1, 'blue');
}
We can break this down into two parts.
A comma-separated list of names. In this case:
(x1, y1, x2, y2, x3, y3)
These are variables which will hold the values passed as arguments when the function is called.
Thus argument lists are a third way of defining variables.
Code enclosed in {}
s. In this case:
{
drawLine(x1, y1, x2, y2, 'blue');
drawLine(x2, y2, x3, y3, 'blue');
drawLine(x3, y3, x1, y1, 'blue');
}
This code will run when the function is called.
When it runs, the variables defined in the argument list will hold the values passed as arguments.
(
arguments) => {
code }
drawTriangle(10, 20, 30, 40, 50, 60);
drawTriangle(10, 20, 30, 40, 10, 40);
Each of these calls replaces six lines of setting up variables and
three lines of calling drawLine
and makes the
meaning of the code much more clear.
Calling a function returns a value.
We’ve seen this already:
Math.sqrt(16)
⟹ 4
In the simple-draw REPL you can evaluate this:
drawLine(0, 0, width, height, 'black')
It will draw a line but the value it returns in the REPL is
undefined
.
Functions that do something, e.g. draw something on the screen or print something out.
Functions that compute a value and return it.
It is generally a good idea to write functions that are one or the other, not both.
drawLine
is the first kindWe call it not to get a value but because it does something we want.
Sometimes we say we call these functions for their side effects.
They usually return undefined
, i.e. no particular
value.
Math.sqrt
is the second kindIt has no side effects but it does return a useful value.
const double = (n) => {
return n * 2;
};
The name is double
. It takes one argument,
n
, and returns the value n
times 2.
double(16)
⟹ 32
return
return
is a special construct in Javascript that causes
a function to immediately return the value of the following
expression.
If the body of the function, as in double
, consists of
just a single return
statement, you can write the
function without the return
and without the
{}
s like this:
const double = (n) => n * 2;
This is equivalent to the earlier version with the explicit
return
.
double(16)
evaluates to 32 which is then multipled by
3, giving us a final value of 96.
In this case the double(16)
is evaluted, as before, to
32 which then becomes the argument to the outer call to
double
which doubles it and returns 64.
Pretty much anything
const manhattanDistance = (x1, y1, x2, y2) => {
const xDistance = Math.abs(x1 - x2);
const yDistance = Math.abs(y1 - y2);
return xDistance + yDistance;
};
These variables only exist within the function body so you don’t have to worry about other variables with the same name elsewhere in your program.
const distance = (a, b) => Math.abs(a - b);
const manhattanDistance = (x1, y1, x2, y2) => {
return distance(x1, x2) + distance(y1, y2);
};