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 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);
};